From 70d0f8a68f276274bd09cf31788185ed02b480b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Sun, 26 Aug 2018 12:46:42 +0200
Subject: [PATCH 001/199] Add return value in hook_exec
---
src/yunohost/hook.py | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/src/yunohost/hook.py b/src/yunohost/hook.py
index 87844ce17..143742df1 100644
--- a/src/yunohost/hook.py
+++ b/src/yunohost/hook.py
@@ -280,8 +280,8 @@ def hook_callback(action, hooks=[], args=None, no_trace=False, chdir=None,
try:
hook_args = pre_callback(name=name, priority=priority,
path=path, args=args)
- hook_exec(path, args=hook_args, chdir=chdir, env=env,
- no_trace=no_trace, raise_on_error=True, user="root")
+ hook_return = hook_exec(path, args=hook_args, chdir=chdir, env=env,
+ no_trace=no_trace, raise_on_error=True, user="root")[1]
except MoulinetteError as e:
state = 'failed'
logger.error(e.strerror, exc_info=1)
@@ -294,6 +294,10 @@ def hook_callback(action, hooks=[], args=None, no_trace=False, chdir=None,
result[state][name].append(path)
except KeyError:
result[state][name] = [path]
+ try:
+ result['stdreturn'].append(hook_return)
+ except KeyError:
+ result['stdreturn'] = [hook_return]
return result
@@ -341,6 +345,11 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
stdinfo = os.path.join(tempfile.mkdtemp(), "stdinfo")
env['YNH_STDINFO'] = stdinfo
+ stdreturn = os.path.join(tempfile.mkdtemp(), "stdreturn")
+ with open(stdreturn, 'w') as f:
+ f.write('')
+ env['YNH_STDRETURN'] = stdreturn
+
# Construct command to execute
if user == "root":
command = ['sh', '-c']
@@ -388,11 +397,18 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
errno.EIO, m18n.n('hook_exec_not_terminated', path=path))
else:
logger.error(m18n.n('hook_exec_not_terminated', path=path))
- return 1
+ return 1, ''
elif raise_on_error and returncode != 0:
raise MoulinetteError(
errno.EIO, m18n.n('hook_exec_failed', path=path))
- return returncode
+
+ with open(stdreturn, 'r') as f:
+ returnstring = f.read()
+ stdreturndir = os.path.split(stdreturn)[0]
+ os.remove(stdreturn)
+ os.rmdir(stdreturndir)
+
+ return returncode, returnstring
def _extract_filename_parts(filename):
From b64196c47ddc80926c4d46717da915bb78833a3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Sun, 26 Aug 2018 12:31:20 +0200
Subject: [PATCH 002/199] Change return of hook_exec everywhere
---
src/yunohost/app.py | 12 ++++++------
src/yunohost/backup.py | 6 +++---
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index 1fed09425..bad1797b3 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -513,7 +513,7 @@ def app_change_url(operation_logger, auth, app, domain, path):
os.system('chmod +x %s' % os.path.join(os.path.join(APP_TMP_FOLDER, "scripts", "change_url")))
if hook_exec(os.path.join(APP_TMP_FOLDER, 'scripts/change_url'),
- args=args_list, env=env_dict, user="root") != 0:
+ args=args_list, env=env_dict, user="root")[0] != 0:
msg = "Failed to change '%s' url." % app
logger.error(msg)
operation_logger.error(msg)
@@ -640,7 +640,7 @@ def app_upgrade(auth, app=[], url=None, file=None):
# Execute App upgrade script
os.system('chown -hR admin: %s' % INSTALL_TMP)
if hook_exec(extracted_app_folder + '/scripts/upgrade',
- args=args_list, env=env_dict, user="root") != 0:
+ args=args_list, env=env_dict, user="root")[0] != 0:
msg = m18n.n('app_upgrade_failed', app=app_instance_name)
logger.error(msg)
operation_logger.error(msg)
@@ -801,7 +801,7 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
install_retcode = hook_exec(
os.path.join(extracted_app_folder, 'scripts/install'),
args=args_list, env=env_dict, user="root"
- )
+ )[0]
except (KeyboardInterrupt, EOFError):
install_retcode = -1
except:
@@ -825,7 +825,7 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
remove_retcode = hook_exec(
os.path.join(extracted_app_folder, 'scripts/remove'),
args=[app_instance_name], env=env_dict_remove, user="root"
- )
+ )[0]
if remove_retcode != 0:
msg = m18n.n('app_not_properly_removed',
app=app_instance_name)
@@ -912,7 +912,7 @@ def app_remove(operation_logger, auth, app):
operation_logger.flush()
if hook_exec('/tmp/yunohost_remove/scripts/remove', args=args_list,
- env=env_dict, user="root") == 0:
+ env=env_dict, user="root")[0] == 0:
logger.success(m18n.n('app_removed', app=app))
hook_callback('post_app_remove', args=args_list, env=env_dict)
@@ -1518,7 +1518,7 @@ def app_action_run(app_id, action, args=None):
env=env_dict,
chdir=cwd,
user=action_declaration.get("user", "root"),
- )
+ )[0]
if retcode not in action_declaration.get("accepted_return_codes", [0]):
raise MoulinetteError(retcode, "Error while executing action '%s' of app '%s': return code %s" % (action, app_id, retcode))
diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py
index 88959cc2f..bad2f53c2 100644
--- a/src/yunohost/backup.py
+++ b/src/yunohost/backup.py
@@ -680,7 +680,7 @@ class BackupManager():
subprocess.call(['install', '-Dm555', app_script, tmp_script])
hook_exec(tmp_script, args=[tmp_app_bkp_dir, app],
- raise_on_error=True, chdir=tmp_app_bkp_dir, env=env_dict, user="root")
+ raise_on_error=True, chdir=tmp_app_bkp_dir, env=env_dict, user="root")[0]
self._import_to_list_to_backup(env_dict["YNH_BACKUP_CSV"])
except:
@@ -1311,7 +1311,7 @@ class RestoreManager():
chdir=app_backup_in_archive,
raise_on_error=True,
env=env_dict,
- user="root")
+ user="root")[0]
except:
msg = m18n.n('restore_app_failed',app=app_instance_name)
logger.exception(msg)
@@ -1336,7 +1336,7 @@ class RestoreManager():
# Execute remove script
# TODO: call app_remove instead
if hook_exec(remove_script, args=[app_instance_name],
- env=env_dict_remove, user="root") != 0:
+ env=env_dict_remove, user="root")[0] != 0:
msg = m18n.n('app_not_properly_removed', app=app_instance_name)
logger.warning(msg)
operation_logger.error(msg)
From b7554dec2176f38df20a0d49a42d522a7c702ff9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Sun, 26 Aug 2018 14:59:26 +0200
Subject: [PATCH 003/199] Use json for return
---
locales/en.json | 1 +
src/yunohost/hook.py | 24 ++++++++++++++++--------
2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/locales/en.json b/locales/en.json
index 074512311..1e7e78490 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -199,6 +199,7 @@
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it's not a type supported by the system.",
"hook_exec_failed": "Script execution failed: {path:s}",
"hook_exec_not_terminated": "Script execution hasn\u2019t terminated: {path:s}",
+ "hook_json_return_error": "Faild to read return from hook {path:s}. Error: {msg:s}",
"hook_list_by_invalid": "Invalid property to list hook by",
"hook_name_unknown": "Unknown hook name '{name:s}'",
"installation_complete": "Installation complete",
diff --git a/src/yunohost/hook.py b/src/yunohost/hook.py
index 143742df1..3ef05980a 100644
--- a/src/yunohost/hook.py
+++ b/src/yunohost/hook.py
@@ -32,6 +32,7 @@ from glob import iglob
from moulinette import m18n
from moulinette.core import MoulinetteError
from moulinette.utils import log
+from moulinette.utils.filesystem import read_json
HOOK_FOLDER = '/usr/share/yunohost/hooks/'
CUSTOM_HOOK_FOLDER = '/etc/yunohost/hooks.d/'
@@ -229,7 +230,7 @@ def hook_callback(action, hooks=[], args=None, no_trace=False, chdir=None,
(name, priority, path, succeed) as arguments
"""
- result = {'succeed': {}, 'failed': {}}
+ result = {'succeed': {}, 'failed': {}, 'stdreturn' : []}
hooks_dict = {}
# Retrieve hooks
@@ -294,10 +295,13 @@ def hook_callback(action, hooks=[], args=None, no_trace=False, chdir=None,
result[state][name].append(path)
except KeyError:
result[state][name] = [path]
- try:
- result['stdreturn'].append(hook_return)
- except KeyError:
- result['stdreturn'] = [hook_return]
+
+ #print(hook_return)
+ #for r in hook_return.:
+ result['stdreturn'].extend(hook_return) #for r in hook_return
+ #print(r)
+
+ #print(result['stdreturn'])
return result
@@ -402,13 +406,17 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
raise MoulinetteError(
errno.EIO, m18n.n('hook_exec_failed', path=path))
- with open(stdreturn, 'r') as f:
- returnstring = f.read()
+ try:
+ returnjson = read_json(stdreturn)
+ except Exception as e:
+ returnjson = {}
+ errno.EIO, m18n.n('hook_json_return_error', path=path, msg=str(e))
+
stdreturndir = os.path.split(stdreturn)[0]
os.remove(stdreturn)
os.rmdir(stdreturndir)
- return returncode, returnstring
+ return returncode, returnjson
def _extract_filename_parts(filename):
From 29bf70c57cd7ec24ac33d5688ccd75b2ac5bd101 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Wed, 29 Aug 2018 18:54:39 +0200
Subject: [PATCH 004/199] Add hook name in return structure in hook_callback
---
src/yunohost/hook.py | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/src/yunohost/hook.py b/src/yunohost/hook.py
index 3ef05980a..efd14ca75 100644
--- a/src/yunohost/hook.py
+++ b/src/yunohost/hook.py
@@ -230,7 +230,6 @@ def hook_callback(action, hooks=[], args=None, no_trace=False, chdir=None,
(name, priority, path, succeed) as arguments
"""
- result = {'succeed': {}, 'failed': {}, 'stdreturn' : []}
hooks_dict = {}
# Retrieve hooks
@@ -292,16 +291,11 @@ def hook_callback(action, hooks=[], args=None, no_trace=False, chdir=None,
post_callback(name=name, priority=priority, path=path,
succeed=True)
try:
- result[state][name].append(path)
+ result[name][state].append(path)
except KeyError:
- result[state][name] = [path]
+ result[name][state] = [path]
- #print(hook_return)
- #for r in hook_return.:
- result['stdreturn'].extend(hook_return) #for r in hook_return
- #print(r)
-
- #print(result['stdreturn'])
+ result[name]['stdreturn'] = hook_return
return result
From e4e981c0fe4e635001619e3bd339aa5c32834954 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Wed, 29 Aug 2018 20:56:00 +0200
Subject: [PATCH 005/199] Change struct returned by hook_callback
---
src/yunohost/hook.py | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/src/yunohost/hook.py b/src/yunohost/hook.py
index efd14ca75..ce83ce011 100644
--- a/src/yunohost/hook.py
+++ b/src/yunohost/hook.py
@@ -230,6 +230,7 @@ def hook_callback(action, hooks=[], args=None, no_trace=False, chdir=None,
(name, priority, path, succeed) as arguments
"""
+ result = {}
hooks_dict = {}
# Retrieve hooks
@@ -290,12 +291,8 @@ def hook_callback(action, hooks=[], args=None, no_trace=False, chdir=None,
else:
post_callback(name=name, priority=priority, path=path,
succeed=True)
- try:
- result[name][state].append(path)
- except KeyError:
- result[name][state] = [path]
- result[name]['stdreturn'] = hook_return
+ result[name] = {'path' : path, 'state' : state, 'stdreturn' : hook_return }
return result
From 439a999c02c172fe1d0299bc3a7f779d719e8a5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Sun, 26 Aug 2018 12:47:15 +0200
Subject: [PATCH 006/199] Add hook support in domain_dns_conf
---
src/yunohost/domain.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 560a6fda5..644b233d2 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -188,6 +188,7 @@ def domain_dns_conf(domain, ttl=None):
ttl -- Time to live
"""
+ from yunohost.hook import hook_callback
ttl = 3600 if ttl is None else ttl
@@ -209,6 +210,11 @@ def domain_dns_conf(domain, ttl=None):
for record in dns_conf["mail"]:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
+ result += "\n\n"
+ result += "; Custom\n"
+
+ result += ''.join(hook_callback('custom_dns_rules', args=[])['stdreturn'])
+
is_cli = True if msettings.get('interface') == 'cli' else False
if is_cli:
logger.info(m18n.n("domain_dns_conf_is_just_a_recommendation"))
From 5a27e314ff78fbc29b8c9849a555732977e9b223 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Sun, 26 Aug 2018 14:59:52 +0200
Subject: [PATCH 007/199] Get custom dns conf in _build_dns_conf
---
src/yunohost/domain.py | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 644b233d2..475b23223 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -38,6 +38,7 @@ import yunohost.certificate
from yunohost.service import service_regen_conf
from yunohost.utils.network import get_public_ip
from yunohost.log import is_unit_operation
+from yunohost.hook import hook_callback
logger = getActionLogger('yunohost.domain')
@@ -188,7 +189,6 @@ def domain_dns_conf(domain, ttl=None):
ttl -- Time to live
"""
- from yunohost.hook import hook_callback
ttl = 3600 if ttl is None else ttl
@@ -212,8 +212,8 @@ def domain_dns_conf(domain, ttl=None):
result += "\n\n"
result += "; Custom\n"
-
- result += ''.join(hook_callback('custom_dns_rules', args=[])['stdreturn'])
+ for record in dns_conf["custom"]:
+ result += "\n{name} {ttl} IN {type} {value}".format(**record)
is_cli = True if msettings.get('interface') == 'cli' else False
if is_cli:
@@ -393,12 +393,22 @@ def _build_dns_conf(domain, ttl=3600):
["_dmarc", ttl, "TXT", '"v=DMARC1; p=none"'],
]
- return {
+ # Custom
+ hookres = hook_callback('custom_dns_rules', args=[domain])
+ print(hookres)
+ custom = []
+ for h in hookres.values() :
+ custom.extend(h['stdreturn'])
+
+ res = {
"basic": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in basic],
"xmpp": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in xmpp],
"mail": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in mail],
+ "custom": custom,
}
+ return res
+
def _get_DKIM(domain):
DKIM_file = '/etc/dkim/{domain}.mail.txt'.format(domain=domain)
From f83e9cae7d24ec8e3ca6c80ce71e7e5503444093 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Wed, 29 Aug 2018 21:49:35 +0200
Subject: [PATCH 008/199] Dns hook : add specific comment for each hook
---
src/yunohost/domain.py | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 475b23223..6c094e80b 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -210,10 +210,12 @@ def domain_dns_conf(domain, ttl=None):
for record in dns_conf["mail"]:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
- result += "\n\n"
- result += "; Custom\n"
- for record in dns_conf["custom"]:
- result += "\n{name} {ttl} IN {type} {value}".format(**record)
+ for name, record_list in dns_conf.items():
+ if name not in ("basic", "xmpp", "mail"):
+ result += "\n\n"
+ result += "; " + name + "\n"
+ for record in record_list:
+ result += "\n{name} {ttl} IN {type} {value}".format(**record)
is_cli = True if msettings.get('interface') == 'cli' else False
if is_cli:
@@ -393,20 +395,18 @@ def _build_dns_conf(domain, ttl=3600):
["_dmarc", ttl, "TXT", '"v=DMARC1; p=none"'],
]
- # Custom
- hookres = hook_callback('custom_dns_rules', args=[domain])
- print(hookres)
- custom = []
- for h in hookres.values() :
- custom.extend(h['stdreturn'])
-
+ # Official record
res = {
"basic": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in basic],
"xmpp": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in xmpp],
"mail": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in mail],
- "custom": custom,
}
+ # Custom record
+ hookres = hook_callback('custom_dns_rules', args=[domain])
+ for n,v in hookres.items() :
+ res[n] = v['stdreturn']
+
return res
From 8ec6f2b81a2ee91e450a3a49d7fa627713d61020 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Thu, 30 Aug 2018 17:37:28 +0200
Subject: [PATCH 009/199] Fix error if hook return nothing
---
src/yunohost/hook.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/hook.py b/src/yunohost/hook.py
index ce83ce011..7ad95c8ab 100644
--- a/src/yunohost/hook.py
+++ b/src/yunohost/hook.py
@@ -398,10 +398,15 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
errno.EIO, m18n.n('hook_exec_failed', path=path))
try:
- returnjson = read_json(stdreturn)
+ with open(stdreturn, 'r') as f:
+ if f.read() != '':
+ returnjson = read_json(stdreturn)
+ else:
+ returnjson = {}
except Exception as e:
returnjson = {}
- errno.EIO, m18n.n('hook_json_return_error', path=path, msg=str(e))
+ raise MoulinetteError(
+ errno.EIO, m18n.n('hook_json_return_error', path=path, msg=str(e)))
stdreturndir = os.path.split(stdreturn)[0]
os.remove(stdreturn)
From a20b72c2dd26db2721a6d9d9b61fcc3ea116abb8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Tue, 4 Sep 2018 22:50:45 +0200
Subject: [PATCH 010/199] Add comment about DNS datastructure returned
---
src/yunohost/domain.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 6c094e80b..a9df20026 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -342,6 +342,9 @@ def _build_dns_conf(domain, ttl=3600):
{"type": "TXT", "name": "mail._domainkey", "value": "\"v=DKIM1; k=rsa; p=some-super-long-key\"", "ttl": 3600},
{"type": "TXT", "name": "_dmarc", "value": "\"v=DMARC1; p=none\"", "ttl": 3600}
],
+ "example_of_a_custom_rule": [
+ {"type": "SRV", "name": "_matrix", "value": "domain.tld.", "ttl": 3600}
+ ],
}
"""
From 8012f12797e7025f6832db6fa60e60db3c8c247a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Wed, 5 Dec 2018 00:32:42 +0100
Subject: [PATCH 011/199] Fix raise error
---
src/yunohost/hook.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/yunohost/hook.py b/src/yunohost/hook.py
index 121630e9f..4e219d226 100644
--- a/src/yunohost/hook.py
+++ b/src/yunohost/hook.py
@@ -404,7 +404,8 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
else:
returnjson = {}
except Exception as e:
- returnjson = {}
+ os.remove(stdreturn)
+ os.rmdir(stdreturndir)
raise MoulinetteError(
errno.EIO, m18n.n('hook_json_return_error', path=path, msg=str(e)))
From f266cceb265559e8bf3d272b1b4837bb2206c08e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Mon, 7 Jan 2019 20:23:41 +0100
Subject: [PATCH 012/199] Fix typo
---
src/yunohost/domain.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 280f8a9c3..088f7724f 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -4,8 +4,7 @@
Copyright (C) 2013 YunoHost
- This progra
- m is free software; you can redistribute it and/or modify
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
From 2e1ccf2b99f9faec47f0455d73cbcc5ea62d15ad Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Mon, 28 Jan 2019 16:20:47 +0100
Subject: [PATCH 013/199] Add ynh_systemd_action helper
---
data/helpers.d/system | 89 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 89 insertions(+)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index 70cc57493..5fe62dcef 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -53,3 +53,92 @@ ynh_abort_if_errors () {
ynh_get_debian_release () {
echo $(lsb_release --codename --short)
}
+
+# Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started
+#
+# usage: ynh_systemd_action [-n service_name] [-a action] [ [-l "line to match"] [-p log_path] [-t timeout] [-e length] ]
+# | arg: -n, --service_name= - Name of the service to reload. Default : $app
+# | arg: -a, --action= - Action to perform with systemctl. Default: start
+# | arg: -l, --line_match= - Line to match - The line to find in the log to attest the service have finished to boot.
+# If not defined it don't wait until the service is completely started.
+# | arg: -p, --log_path= - Log file - Path to the log file. Default : /var/log/$app/$app.log
+# | arg: -t, --timeout= - Timeout - The maximum time to wait before ending the watching. Default : 300 seconds.
+# | arg: -e, --length= - Length of the error log : Default : 20
+ynh_systemd_action() {
+ # Declare an array to define the options of this helper.
+ declare -Ar args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= )
+ local service_name
+ local action
+ local line_match
+ local length
+ local log_path
+ local timeout
+
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+
+ local service_name="${service_name:-$app}"
+ local action=${action:-start}
+ local log_path="${log_path:-/var/log/$service_name/$service_name.log}"
+ local length=${length:-20}
+ local timeout=${timeout:-300}
+
+ # Start to read the log
+ if [[ -n "${line_match:-}" ]]
+ then
+ local templog="$(mktemp)"
+ # Following the starting of the app in its log
+ if [ "$log_path" == "systemd" ] ; then
+ # Read the systemd journal
+ journalctl -u $service_name -f --since=-45 > "$templog" &
+ else
+ # Read the specified log file
+ tail -F -n0 "$log_path" > "$templog" &
+ fi
+ # Get the PID of the tail command
+ local pid_tail=$!
+ fi
+
+ echo "${action^} the service $service_name" >&2
+ systemctl $action $service_name \
+ || ( journalctl --lines=$length -u $service_name >&2 \
+ ; test -n "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2 \
+ ; false )
+
+ # Start the timeout and try to find line_match
+ if [[ -n "${line_match:-}" ]]
+ then
+ local i=0
+ for i in $(seq 1 $timeout)
+ do
+ # Read the log until the sentence is found, that means the app finished to start. Or run until the timeout
+ if grep --quiet "$line_match" "$templog"
+ then
+ echo "The service $service_name has correctly started." >&2
+ break
+ fi
+ echo -n "." >&2
+ sleep 1
+ done
+ if [ $i -eq $timeout ]
+ then
+ echo "The service $service_name didn't fully started before the timeout." >&2
+ echo "Please find here an extract of the end of the log of the service $service_name:"
+ journalctl --lines=$length -u $service_name >&2
+ test -n "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2
+ fi
+
+ echo ""
+ ynh_clean_check_starting
+ fi
+}
+
+# Clean temporary process and file used by ynh_check_starting
+# (usually used in ynh_clean_setup scripts)
+#
+# usage: ynh_clean_check_starting
+ynh_clean_check_starting () {
+ # Stop the execution of tail.
+ kill -s 15 $pid_tail 2>&1
+ ynh_secure_remove "$templog" 2>&1
+}
From 35ffadbe1c7f5967a485f1282257d7244e9641f1 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Mon, 28 Jan 2019 16:26:43 +0100
Subject: [PATCH 014/199] Use ynh_systemd_action for backend helpers
---
data/helpers.d/backend | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/data/helpers.d/backend b/data/helpers.d/backend
index e73644d2d..8d353365d 100644
--- a/data/helpers.d/backend
+++ b/data/helpers.d/backend
@@ -117,10 +117,10 @@ ynh_remove_systemd_config () {
local finalsystemdconf="/etc/systemd/system/$service_name.service"
if [ -e "$finalsystemdconf" ]; then
- sudo systemctl stop $service_name
- sudo systemctl disable $service_name
+ ynh_systemd_action --service_name=$service_name --action=stop
+ systemctl disable $service_name
ynh_secure_remove "$finalsystemdconf"
- sudo systemctl daemon-reload
+ systemctl daemon-reload
fi
}
@@ -186,7 +186,7 @@ ynh_add_nginx_config () {
ynh_store_file_checksum "$finalnginxconf"
- sudo systemctl reload nginx
+ ynh_systemd_action --service_name=nginx --action=reload
}
# Remove the dedicated nginx config
@@ -194,7 +194,7 @@ ynh_add_nginx_config () {
# usage: ynh_remove_nginx_config
ynh_remove_nginx_config () {
ynh_secure_remove "/etc/nginx/conf.d/$domain.d/$app.conf"
- sudo systemctl reload nginx
+ ynh_systemd_action --service_name=nginx --action=reload
}
# Create a dedicated php-fpm config
@@ -229,7 +229,7 @@ ynh_add_fpm_config () {
sudo chown root: "$finalphpini"
ynh_store_file_checksum "$finalphpini"
fi
- sudo systemctl reload $fpm_service
+ ynh_systemd_action --service_name=$fpm_service --action=reload
}
# Remove the dedicated php-fpm config
@@ -245,5 +245,5 @@ ynh_remove_fpm_config () {
fi
ynh_secure_remove "$fpm_config_dir/pool.d/$app.conf"
ynh_secure_remove "$fpm_config_dir/conf.d/20-$app.ini" 2>&1
- sudo systemctl reload $fpm_service
+ ynh_systemd_action --service_name=$fpm_service --action=reload
}
From 66ef3e208bbac0472ae583c6ef4e18013e892b64 Mon Sep 17 00:00:00 2001
From: Taekiro
Date: Sun, 3 Feb 2019 09:54:48 +0100
Subject: [PATCH 015/199] Add IPv6 nameserver to resolv.dnsmasq.conf
---
data/templates/dnsmasq/plain/resolv.dnsmasq.conf | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/data/templates/dnsmasq/plain/resolv.dnsmasq.conf b/data/templates/dnsmasq/plain/resolv.dnsmasq.conf
index 7eed1142f..197ee2d64 100644
--- a/data/templates/dnsmasq/plain/resolv.dnsmasq.conf
+++ b/data/templates/dnsmasq/plain/resolv.dnsmasq.conf
@@ -9,25 +9,37 @@
# (FR) FDN
nameserver 80.67.169.12
+nameserver 2001:910:800::12
nameserver 80.67.169.40
+nameserver 2001:910:800::40
# (FR) LDN
nameserver 80.67.188.188
+nameserver 2001:913::8
# (FR) ARN
nameserver 89.234.141.66
+nameserver 2a00:5881:8100:1000::3
# (FR) Aquilenet
nameserver 185.233.100.100
+nameserver 2a0c:e300::100
nameserver 185.233.100.101
+nameserver 2a0c:e300::101
# (FR) gozmail / grifon
nameserver 80.67.190.200
+nameserver 2a00:5884:8218::1
# (DE) FoeBud / Digital Courage
nameserver 85.214.20.141
# (DE) CCC Berlin
nameserver 195.160.173.53
# (DE) AS250
nameserver 194.150.168.168
+nameserver 2001:4ce8::53
# (DE) Ideal-Hosting
nameserver 84.200.69.80
+nameserver 2001:1608:10:25::1c04:b12f
nameserver 84.200.70.40
+nameserver 2001:1608:10:25::9249:d69b
# (DK) censurfridns
nameserver 91.239.100.100
+nameserver 2001:67c:28a4::
nameserver 89.233.43.71
+nameserver 2002:d596:2a92:1:71:53::
From 8e1034771af5ecc9acce6e9966ac077ec2ea36c7 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Mon, 4 Feb 2019 23:01:16 +0100
Subject: [PATCH 016/199] use setting security_ciphers_compatibility to define
security configurations
---
data/hooks/conf_regen/03-ssh | 8 +++++++-
data/hooks/conf_regen/15-nginx | 6 ++++++
data/templates/nginx/server.tpl.conf | 20 ++++++++++++--------
data/templates/ssh/sshd_config | 15 +++++++++++----
4 files changed, 36 insertions(+), 13 deletions(-)
diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh
index 9de527518..330166f08 100755
--- a/data/hooks/conf_regen/03-ssh
+++ b/data/hooks/conf_regen/03-ssh
@@ -12,7 +12,7 @@ do_pre_regen() {
[[ ! -f /etc/yunohost/from_script ]] || return 0
cd /usr/share/yunohost/templates/ssh
-
+
# do not listen to IPv6 if unavailable
[[ -f /proc/net/if_inet6 ]] && ipv6_enabled=true || ipv6_enabled=false
@@ -23,8 +23,14 @@ do_pre_regen() {
ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null || true)"
fi
+ # Support different strategy for security configurations
+ if [[ -n "$(yunohost settings get 'security.ciphers.compatibility')" ]]; then
+ security_ciphers_compatibility="$(yunohost settings get 'security.ciphers.compatibility')"
+ fi
+
export ssh_keys
export ipv6_enabled
+ export security_ciphers_compatibility
ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config"
}
diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx
index 461c10c0c..97543dcfa 100755
--- a/data/hooks/conf_regen/15-nginx
+++ b/data/hooks/conf_regen/15-nginx
@@ -36,6 +36,11 @@ do_pre_regen() {
main_domain=$(cat /etc/yunohost/current_host)
domain_list=$(sudo yunohost domain list --output-as plain --quiet)
+ # Support different strategy for security configurations
+ if [[ -n "$(yunohost settings get 'security.ciphers.compatibility')" ]]; then
+ security_ciphers_compatibility="$(yunohost settings get 'security.ciphers.compatibility')"
+ fi
+
# add domain conf files
for domain in $domain_list; do
domain_conf_dir="${nginx_conf_dir}/${domain}.d"
@@ -44,6 +49,7 @@ do_pre_regen() {
mkdir -p "$mail_autoconfig_dir"
# NGINX server configuration
+ export security_ciphers_compatibility
export domain
export domain_cert_ca=$(yunohost domain cert-status $domain --json \
| jq ".certificates.\"$domain\".CA_type" \
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index 0c221f188..50ee1b9b8 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -29,6 +29,15 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
+ {%- if security_ciphers_compatibility == "modern" -%}
+ # Ciphers with modern compatibility
+ # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
+ # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
+ ssl_protocols TLSv1.2;
+ ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
+ ssl_prefer_server_ciphers on;
+
+ {%- else -%}
# As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519
ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
ssl_prefer_server_ciphers on;
@@ -38,20 +47,15 @@ server {
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
- # Ciphers with modern compatibility
- # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
- # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
- #ssl_protocols TLSv1.2;
- #ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
-
# Uncomment the following directive after DH generation
# > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
#ssl_dhparam /etc/ssl/private/dh2048.pem;
+ {%- endif -%}
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
- # https://observatory.mozilla.org/
- more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
+ # https://observatory.mozilla.org/
+ more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
more_set_headers "Content-Security-Policy : upgrade-insecure-requests";
more_set_headers "Content-Security-Policy-Report-Only : default-src https: data: 'unsafe-inline' 'unsafe-eval'";
more_set_headers "X-Content-Type-Options : nosniff";
diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config
index ed870e5dc..7194a309d 100644
--- a/data/templates/ssh/sshd_config
+++ b/data/templates/ssh/sshd_config
@@ -15,10 +15,17 @@ HostKey {{ key }}{% endfor %}
# https://infosec.mozilla.org/guidelines/openssh
# ##############################################
-# Keys, ciphers and MACS
-KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
-Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
-MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
+{%- if security_ciphers_compatibility == "intermediate" -%}
+ KexAlgorithms diffie-hellman-group-exchange-sha256
+ Ciphers aes256-ctr,aes192-ctr,aes128-ctr
+ MACs hmac-sha2-512,hmac-sha2-256
+{%- else -%}
+ # By default use "modern" Mozilla configuration
+ # Keys, ciphers and MACS
+ KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
+ Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
+ MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
+{%- endif -%}
# Use kernel sandbox mechanisms where possible in unprivileged processes
UsePrivilegeSeparation sandbox
From 1895e1ac6339c1e1a4547c509108c606a88a4ce1 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Wed, 6 Feb 2019 11:18:16 +0100
Subject: [PATCH 017/199] since 0 instead of since 45
---
data/helpers.d/system | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index 5fe62dcef..25d135401 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -90,7 +90,7 @@ ynh_systemd_action() {
# Following the starting of the app in its log
if [ "$log_path" == "systemd" ] ; then
# Read the systemd journal
- journalctl -u $service_name -f --since=-45 > "$templog" &
+ journalctl --unit=$service_name --follow --since=-0 --quiet > "$templog" &
else
# Read the specified log file
tail -F -n0 "$log_path" > "$templog" &
From 8e8ed223951d56c9f115efbe008b6b110a0ec4a7 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Sat, 9 Feb 2019 11:38:15 +0100
Subject: [PATCH 018/199] Fix usage of $service_name
---
data/helpers.d/backend | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/backend b/data/helpers.d/backend
index 66f10baba..95ef95820 100644
--- a/data/helpers.d/backend
+++ b/data/helpers.d/backend
@@ -158,8 +158,8 @@ ynh_remove_systemd_config () {
local finalsystemdconf="/etc/systemd/system/$service.service"
if [ -e "$finalsystemdconf" ]; then
- ynh_systemd_action --service_name=$service_name --action=stop
- systemctl disable $service_name
+ ynh_systemd_action --service_name=$service --action=stop
+ systemctl disable $service
ynh_secure_remove --file="$finalsystemdconf"
systemctl daemon-reload
fi
From e0aaf6f8a160f7b2028635e9e1b7235eca6bc4c7 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Sat, 9 Feb 2019 11:56:33 +0100
Subject: [PATCH 019/199] add trace for process check
---
data/hooks/conf_regen/15-nginx | 1 +
1 file changed, 1 insertion(+)
diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx
index 97543dcfa..f0ca11797 100755
--- a/data/hooks/conf_regen/15-nginx
+++ b/data/hooks/conf_regen/15-nginx
@@ -49,6 +49,7 @@ do_pre_regen() {
mkdir -p "$mail_autoconfig_dir"
# NGINX server configuration
+ echo "RDS Using security_ciphers_compatibility=$security_ciphers_compatibility"
export security_ciphers_compatibility
export domain
export domain_cert_ca=$(yunohost domain cert-status $domain --json \
From fc0e3d4830ddbcf1565380833e30292dffa1f322 Mon Sep 17 00:00:00 2001
From: Taekiro
Date: Sat, 9 Feb 2019 16:37:23 +0100
Subject: [PATCH 020/199] Allow query to local IPv6
---
data/templates/dnsmasq/plain/dnsmasq.conf | 1 +
1 file changed, 1 insertion(+)
diff --git a/data/templates/dnsmasq/plain/dnsmasq.conf b/data/templates/dnsmasq/plain/dnsmasq.conf
index 12a14048a..2dc7775e1 100644
--- a/data/templates/dnsmasq/plain/dnsmasq.conf
+++ b/data/templates/dnsmasq/plain/dnsmasq.conf
@@ -2,5 +2,6 @@ domain-needed
expand-hosts
listen-address=127.0.0.1
+listen-address=::1
resolv-file=/etc/resolv.dnsmasq.conf
cache-size=256
From d0fbcb43454397dc98d0aef64327e5bd2d60276d Mon Sep 17 00:00:00 2001
From: Taekiro
Date: Sat, 9 Feb 2019 16:42:59 +0100
Subject: [PATCH 021/199] Update dnsmasq.conf
---
data/templates/dnsmasq/plain/dnsmasq.conf | 1 -
1 file changed, 1 deletion(-)
diff --git a/data/templates/dnsmasq/plain/dnsmasq.conf b/data/templates/dnsmasq/plain/dnsmasq.conf
index 2dc7775e1..12a14048a 100644
--- a/data/templates/dnsmasq/plain/dnsmasq.conf
+++ b/data/templates/dnsmasq/plain/dnsmasq.conf
@@ -2,6 +2,5 @@ domain-needed
expand-hosts
listen-address=127.0.0.1
-listen-address=::1
resolv-file=/etc/resolv.dnsmasq.conf
cache-size=256
From f084de5a69e7edd353ab90b7bf999775bbd234e0 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Sat, 9 Feb 2019 23:30:40 +0100
Subject: [PATCH 022/199] declare setting security.ciphers.compatibility
---
locales/en.json | 1 +
locales/fr.json | 1 +
src/yunohost/settings.py | 1 +
3 files changed, 3 insertions(+)
diff --git a/locales/en.json b/locales/en.json
index 8528c2576..72a34fb57 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -202,6 +202,7 @@
"global_settings_setting_example_enum": "Example enum option",
"global_settings_setting_example_int": "Example int option",
"global_settings_setting_example_string": "Example string option",
+ "global_settings_setting_security_ciphers_compatibility": "Admin ciphers compatibility strategy",
"global_settings_setting_security_password_admin_strength": "Admin password strength",
"global_settings_setting_security_password_user_strength": "User password strength",
"global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding it and save it in /etc/yunohost/unkown_settings.json",
diff --git a/locales/fr.json b/locales/fr.json
index 7119039db..0c73cebcd 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -308,6 +308,7 @@
"global_settings_setting_example_int": "Exemple d’option de type entier",
"global_settings_setting_example_string": "Exemple d’option de type chaîne",
"global_settings_setting_example_enum": "Exemple d’option de type énumération",
+ "global_settings_setting_security_ciphers_compatibility": "Stratégie de compatibilité des ciphers",
"global_settings_unknown_type": "Situation inattendue, la configuration {setting:s} semble avoir le type {unknown_type:s} mais ce n’est pas un type pris en charge par le système.",
"global_settings_unknown_setting_from_settings_file": "Clef inconnue dans les configurations : {setting_key:s}, rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index bbfb3ca56..7826b620f 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -39,6 +39,7 @@ DEFAULTS = OrderedDict([
("security.password.admin.strength", {"type": "int", "default": 1}),
("security.password.user.strength", {"type": "int", "default": 1}),
("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}),
+ ("security.ciphers.compatibility", {"type": "string", "default": "intermediate"}),
])
From 6ab5d716037b76a913c30a43b6ad1e2d57870428 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Mon, 11 Feb 2019 20:05:21 +0100
Subject: [PATCH 023/199] Add the possibility to have multiple path per hook
name
---
src/yunohost/hook.py | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/yunohost/hook.py b/src/yunohost/hook.py
index 02e3cb2dd..d9cad9c7a 100644
--- a/src/yunohost/hook.py
+++ b/src/yunohost/hook.py
@@ -283,14 +283,16 @@ def hook_callback(action, hooks=[], args=None, no_trace=False, chdir=None,
no_trace=no_trace, raise_on_error=True)[1]
except YunohostError as e:
state = 'failed'
+ hook_return = {}
logger.error(e.strerror, exc_info=1)
post_callback(name=name, priority=priority, path=path,
succeed=False)
else:
post_callback(name=name, priority=priority, path=path,
succeed=True)
-
- result[name] = {'path' : path, 'state' : state, 'stdreturn' : hook_return }
+ if not name in result:
+ result[name] = {}
+ result[name][path] = {'state' : state, 'stdreturn' : hook_return }
return result
@@ -389,7 +391,7 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
raise YunohostError('hook_exec_not_terminated', path=path)
else:
logger.error(m18n.n('hook_exec_not_terminated', path=path))
- return 1, ''
+ return 1, {}
elif raise_on_error and returncode != 0:
raise YunohostError('hook_exec_failed', path=path)
From d15092a7401001ffbe8fcceec168bab0657ea439 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Mon, 11 Feb 2019 20:22:42 +0100
Subject: [PATCH 024/199] Fix result from hook_callback
---
src/yunohost/domain.py | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 088f7724f..66f17c491 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -206,16 +206,16 @@ def domain_dns_conf(domain, ttl=None):
result += "; Mail"
for record in dns_conf["mail"]:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
- result += "\n\n
+ result += "\n\n"
result += "; Extra"
for record in dns_conf["extra"]:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
for name, record_list in dns_conf.items():
- if name not in ("basic", "xmpp", "mail"):
+ if name not in ("basic", "xmpp", "mail", "extra") and record_list:
result += "\n\n"
- result += "; " + name + "\n"
+ result += "; " + name
for record in record_list:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
@@ -418,8 +418,10 @@ def _build_dns_conf(domain, ttl=3600):
# Custom record
hookres = hook_callback('custom_dns_rules', args=[domain])
- for n,v in hookres.items() :
- res[n] = v['stdreturn']
+ for n, val in hookres.items() :
+ res[n] = []
+ for v in [v['stdreturn'] for p, v in val.items() if v and v['stdreturn']]:
+ res[n].extend(v)
return res
From 37a2cc2e1c155f420f283d05bb0eecdf7ad6d1a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Mon, 11 Feb 2019 20:05:50 +0100
Subject: [PATCH 025/199] Adapt the service and backup to support new result of
hook_callback result
---
src/yunohost/backup.py | 30 +++++++++++++++++++-----------
src/yunohost/service.py | 5 +++--
2 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py
index 3874a4461..d33f75e3a 100644
--- a/src/yunohost/backup.py
+++ b/src/yunohost/backup.py
@@ -593,8 +593,11 @@ class BackupManager():
env=env_dict,
chdir=self.work_dir)
- if ret["succeed"] != []:
- self.system_return = ret["succeed"]
+ ret_succeed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "succeed"] for n, v in ret.items()}.items() if val}
+ ret_failed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "failed"] for n, v in ret.items()}.items() if val}
+
+ if ret_succeed != []:
+ self.system_return = ret_succeed
# Add files from targets (which they put in the CSV) to the list of
# files to backup
@@ -610,7 +613,7 @@ class BackupManager():
restore_hooks = hook_list("restore")["hooks"]
- for part in ret['succeed'].keys():
+ for part in ret_succeed.keys():
if part in restore_hooks:
part_restore_hooks = hook_info("restore", part)["hooks"]
for hook in part_restore_hooks:
@@ -620,7 +623,7 @@ class BackupManager():
logger.warning(m18n.n('restore_hook_unavailable', hook=part))
self.targets.set_result("system", part, "Warning")
- for part in ret['failed'].keys():
+ for part in ret_failed.keys():
logger.error(m18n.n('backup_system_part_failed', part=part))
self.targets.set_result("system", part, "Error")
@@ -1177,16 +1180,19 @@ class RestoreManager():
env=env_dict,
chdir=self.work_dir)
- for part in ret['succeed'].keys():
+ ret_succeed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "succeed"] for n, v in ret.items()}.items() if val}
+ ret_failed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "failed"] for n, v in ret.items()}.items() if val}
+
+ for part in ret_succeed.keys():
self.targets.set_result("system", part, "Success")
error_part = []
- for part in ret['failed'].keys():
+ for part in ret_failed.keys():
logger.error(m18n.n('restore_system_part_failed', part=part))
self.targets.set_result("system", part, "Error")
error_part.append(part)
- if ret['failed']:
+ if ret_failed:
operation_logger.error(m18n.n('restore_system_part_failed', part=', '.join(error_part)))
else:
operation_logger.success()
@@ -1929,8 +1935,8 @@ class CustomBackupMethod(BackupMethod):
ret = hook_callback('backup_method', [self.method],
args=self._get_args('need_mount'))
-
- self._need_mount = True if ret['succeed'] else False
+ ret_succeed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "succeed"] for n, v in ret.items()}.items() if val}
+ self._need_mount = True if ret_succeed else False
return self._need_mount
def backup(self):
@@ -1943,7 +1949,8 @@ class CustomBackupMethod(BackupMethod):
ret = hook_callback('backup_method', [self.method],
args=self._get_args('backup'))
- if ret['failed']:
+ ret_failed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "failed"] for n, v in ret.items()}.items() if val}
+ if ret_failed:
raise YunohostError('backup_custom_backup_error')
def mount(self, restore_manager):
@@ -1956,7 +1963,8 @@ class CustomBackupMethod(BackupMethod):
super(CustomBackupMethod, self).mount(restore_manager)
ret = hook_callback('backup_method', [self.method],
args=self._get_args('mount'))
- if ret['failed']:
+ ret_failed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "failed"] for n, v in ret.items()}.items() if val}
+ if ret_failed:
raise YunohostError('backup_custom_mount_error')
def _get_args(self, action):
diff --git a/src/yunohost/service.py b/src/yunohost/service.py
index 60729053b..151a877b9 100644
--- a/src/yunohost/service.py
+++ b/src/yunohost/service.py
@@ -494,11 +494,12 @@ def service_regen_conf(operation_logger, names=[], with_diff=False, force=False,
pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call)
# Update the services name
- names = pre_result['succeed'].keys()
+ names = {n: [p for p, c in v.items() if c['state'] == "failed"] for n, v in pre_result.items()}.keys()
if not names:
+ ret_failed = {n: [p for p, c in v.items() if c['state'] == "failed"] for n, v in pre_result.items()}
raise YunohostError('service_regenconf_failed',
- services=', '.join(pre_result['failed']))
+ services=', '.join(ret_failed))
# Set the processing method
_regen = _process_regen_conf if not dry_run else lambda *a, **k: True
From e776c777e602f76f614659353d9e0f8d84acb387 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 21:17:13 +0100
Subject: [PATCH 026/199] remove strip whitespace syntax
---
data/templates/nginx/server.tpl.conf | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index 50ee1b9b8..2d161d79c 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -29,7 +29,7 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
- {%- if security_ciphers_compatibility == "modern" -%}
+ {% if security_ciphers_compatibility == "modern" %}
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
# Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
@@ -37,7 +37,7 @@ server {
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
- {%- else -%}
+ {% else %}
# As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519
ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
ssl_prefer_server_ciphers on;
@@ -50,7 +50,7 @@ server {
# Uncomment the following directive after DH generation
# > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
#ssl_dhparam /etc/ssl/private/dh2048.pem;
- {%- endif -%}
+ {% endif %}
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
From 3251189ab8529e34c455f38b2b88d60fe47b8208 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 21:26:25 +0100
Subject: [PATCH 027/199] what a cumbersome whitespace control
---
data/templates/nginx/server.tpl.conf | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index 2d161d79c..5f22c8df5 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -29,14 +29,13 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
- {% if security_ciphers_compatibility == "modern" %}
+ {% if security_ciphers_compatibility == "modern" -%}
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
# Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
-
{% else %}
# As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519
ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
@@ -64,7 +63,7 @@ server {
more_set_headers "X-Permitted-Cross-Domain-Policies : none";
more_set_headers "X-Frame-Options : SAMEORIGIN";
- {% if domain_cert_ca == "Let's Encrypt" %}
+ {% if domain_cert_ca == "Let's Encrypt" -%}
# OCSP settings
ssl_stapling on;
ssl_stapling_verify on;
From a267e1bc74167f07bb521162f4e92b225336e89d Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 21:28:56 +0100
Subject: [PATCH 028/199] what a cumbersome whitespace control
---
data/templates/nginx/server.tpl.conf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index 5f22c8df5..9d662b904 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -70,7 +70,7 @@ server {
ssl_trusted_certificate /etc/yunohost/certs/{{ domain }}/crt.pem;
resolver 127.0.0.1 127.0.1.1 valid=300s;
resolver_timeout 5s;
- {% endif %}
+ {%- endif %}
access_by_lua_file /usr/share/ssowat/access.lua;
From 7b01ccfefbc534c34b31dcb3367ebf629b01353c Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 21:33:36 +0100
Subject: [PATCH 029/199] remove whitespace control attempt
---
data/templates/nginx/server.tpl.conf | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index 9d662b904..e19bab970 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -29,7 +29,7 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
- {% if security_ciphers_compatibility == "modern" -%}
+ {% if security_ciphers_compatibility == "modern" %}
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
# Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
@@ -63,14 +63,14 @@ server {
more_set_headers "X-Permitted-Cross-Domain-Policies : none";
more_set_headers "X-Frame-Options : SAMEORIGIN";
- {% if domain_cert_ca == "Let's Encrypt" -%}
+ {% if domain_cert_ca == "Let's Encrypt" %}
# OCSP settings
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/yunohost/certs/{{ domain }}/crt.pem;
resolver 127.0.0.1 127.0.1.1 valid=300s;
resolver_timeout 5s;
- {%- endif %}
+ {% endif %}
access_by_lua_file /usr/share/ssowat/access.lua;
From e9274ee44376cbdcb617f7aa9622d93f6672145a Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 22:27:49 +0100
Subject: [PATCH 030/199] Handle yunohost admin nginx config
---
.../templates/nginx/plain/yunohost_admin.conf | 21 +++++++++++--------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/data/templates/nginx/plain/yunohost_admin.conf b/data/templates/nginx/plain/yunohost_admin.conf
index b6fabf8e3..7992b2de9 100644
--- a/data/templates/nginx/plain/yunohost_admin.conf
+++ b/data/templates/nginx/plain/yunohost_admin.conf
@@ -20,6 +20,14 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
+ {% if security_ciphers_compatibility == "modern" %}
+ # Ciphers with modern compatibility
+ # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
+ # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
+ ssl_protocols TLSv1.2;
+ ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
+ ssl_prefer_server_ciphers on;
+ {% else %}
# As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519
ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
ssl_prefer_server_ciphers on;
@@ -29,20 +37,15 @@ server {
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
- # Ciphers with modern compatibility
- # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
- # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
- #ssl_protocols TLSv1.2;
- #ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
-
# Uncomment the following directive after DH generation
# > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
#ssl_dhparam /etc/ssl/private/dh2048.pem;
-
+ {% endif %}
+
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
- # https://observatory.mozilla.org/
- more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
+ # https://observatory.mozilla.org/
+ more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
more_set_headers "Referrer-Policy : 'same-origin'";
more_set_headers "Content-Security-Policy : upgrade-insecure-requests; object-src 'none'; script-src https: 'unsafe-eval'";
more_set_headers "X-Content-Type-Options : nosniff";
From 12d0e0e1de00463fb13c468ef1403e6761a3cda7 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 22:34:35 +0100
Subject: [PATCH 031/199] add instruction to rebuild yunohost-admin conf
---
data/hooks/conf_regen/15-nginx | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx
index f0ca11797..4c5bac331 100755
--- a/data/hooks/conf_regen/15-nginx
+++ b/data/hooks/conf_regen/15-nginx
@@ -41,6 +41,8 @@ do_pre_regen() {
security_ciphers_compatibility="$(yunohost settings get 'security.ciphers.compatibility')"
fi
+ export security_ciphers_compatibility
+
# add domain conf files
for domain in $domain_list; do
domain_conf_dir="${nginx_conf_dir}/${domain}.d"
@@ -49,8 +51,6 @@ do_pre_regen() {
mkdir -p "$mail_autoconfig_dir"
# NGINX server configuration
- echo "RDS Using security_ciphers_compatibility=$security_ciphers_compatibility"
- export security_ciphers_compatibility
export domain
export domain_cert_ca=$(yunohost domain cert-status $domain --json \
| jq ".certificates.\"$domain\".CA_type" \
@@ -64,6 +64,7 @@ do_pre_regen() {
|| cp yunohost_local.conf "${domain_conf_dir}/yunohost_local.conf"
done
+ ynh_render_template "plain/yunohost_admin.conf" "${nginx_conf_dir}/yunohost-admin.conf"
# remove old domain conf files
conf_files=$(ls -1 /etc/nginx/conf.d \
From ec52ded7776cc481c7563edce790a1c20d5ee09e Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 22:38:28 +0100
Subject: [PATCH 032/199] don't conflict translation tool
---
locales/fr.json | 1 -
1 file changed, 1 deletion(-)
diff --git a/locales/fr.json b/locales/fr.json
index 0c73cebcd..7119039db 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -308,7 +308,6 @@
"global_settings_setting_example_int": "Exemple d’option de type entier",
"global_settings_setting_example_string": "Exemple d’option de type chaîne",
"global_settings_setting_example_enum": "Exemple d’option de type énumération",
- "global_settings_setting_security_ciphers_compatibility": "Stratégie de compatibilité des ciphers",
"global_settings_unknown_type": "Situation inattendue, la configuration {setting:s} semble avoir le type {unknown_type:s} mais ce n’est pas un type pris en charge par le système.",
"global_settings_unknown_setting_from_settings_file": "Clef inconnue dans les configurations : {setting_key:s}, rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
From e8eff8729792d9ef27cf8b829687206c941cd987 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 22:49:13 +0100
Subject: [PATCH 033/199] switch to enum type to store cipher policy setting
---
src/yunohost/settings.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 7826b620f..9b12647a6 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -39,7 +39,7 @@ DEFAULTS = OrderedDict([
("security.password.admin.strength", {"type": "int", "default": 1}),
("security.password.user.strength", {"type": "int", "default": 1}),
("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}),
- ("security.ciphers.compatibility", {"type": "string", "default": "intermediate"}),
+ ("security.ciphers.compatibility", {"type": "enum", "choices": "intermediate", "modern"}),
])
From a899102efc8a13fcf4c16bf31bb7769f4d820b23 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 22:57:24 +0100
Subject: [PATCH 034/199] don't share setting for nginx and ssh
---
data/hooks/conf_regen/03-ssh | 6 +++---
data/templates/ssh/sshd_config | 6 +++---
locales/en.json | 3 ++-
src/yunohost/settings.py | 1 +
4 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh
index 330166f08..3a79de456 100755
--- a/data/hooks/conf_regen/03-ssh
+++ b/data/hooks/conf_regen/03-ssh
@@ -24,13 +24,13 @@ do_pre_regen() {
fi
# Support different strategy for security configurations
- if [[ -n "$(yunohost settings get 'security.ciphers.compatibility')" ]]; then
- security_ciphers_compatibility="$(yunohost settings get 'security.ciphers.compatibility')"
+ if [[ -n "$(yunohost settings get 'service.ssh.ciphers.compatibility')" ]]; then
+ ssh_ciphers_compatibility="$(yunohost settings get 'service.ssh.ciphers.compatibility')"
fi
export ssh_keys
export ipv6_enabled
- export security_ciphers_compatibility
+ export ssh_ciphers_compatibility
ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config"
}
diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config
index 7194a309d..f27ca3ebe 100644
--- a/data/templates/ssh/sshd_config
+++ b/data/templates/ssh/sshd_config
@@ -15,17 +15,17 @@ HostKey {{ key }}{% endfor %}
# https://infosec.mozilla.org/guidelines/openssh
# ##############################################
-{%- if security_ciphers_compatibility == "intermediate" -%}
+{% if ssh_ciphers_compatibility == "intermediate" %}
KexAlgorithms diffie-hellman-group-exchange-sha256
Ciphers aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512,hmac-sha2-256
-{%- else -%}
+{% else %}
# By default use "modern" Mozilla configuration
# Keys, ciphers and MACS
KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
-{%- endif -%}
+{% endif %}
# Use kernel sandbox mechanisms where possible in unprivileged processes
UsePrivilegeSeparation sandbox
diff --git a/locales/en.json b/locales/en.json
index 72a34fb57..3f01cb08e 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -202,11 +202,12 @@
"global_settings_setting_example_enum": "Example enum option",
"global_settings_setting_example_int": "Example int option",
"global_settings_setting_example_string": "Example string option",
- "global_settings_setting_security_ciphers_compatibility": "Admin ciphers compatibility strategy",
+ "global_settings_setting_security_ciphers_compatibility": "Admin ciphers compatibility strategy for the web",
"global_settings_setting_security_password_admin_strength": "Admin password strength",
"global_settings_setting_security_password_user_strength": "User password strength",
"global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding it and save it in /etc/yunohost/unkown_settings.json",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration",
+ "global_settings_setting_service_ssh_ciphers_compatibility": "Admin ciphers compatibility strategy for SSH",
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it's not a type supported by the system.",
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 9b12647a6..c3d4591b0 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -39,6 +39,7 @@ DEFAULTS = OrderedDict([
("security.password.admin.strength", {"type": "int", "default": 1}),
("security.password.user.strength", {"type": "int", "default": 1}),
("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}),
+ ("service.ssh.ciphers.compatibility", {"type": "enum", "choices": "intermediate", "modern"}),
("security.ciphers.compatibility", {"type": "enum", "choices": "intermediate", "modern"}),
])
From 375b7d53b1fca626abdba882799692aa247ab1e8 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 23:00:52 +0100
Subject: [PATCH 035/199] fix enum syntax
---
src/yunohost/settings.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index c3d4591b0..1d60c3a6a 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -39,8 +39,10 @@ DEFAULTS = OrderedDict([
("security.password.admin.strength", {"type": "int", "default": 1}),
("security.password.user.strength", {"type": "int", "default": 1}),
("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}),
- ("service.ssh.ciphers.compatibility", {"type": "enum", "choices": "intermediate", "modern"}),
- ("security.ciphers.compatibility", {"type": "enum", "choices": "intermediate", "modern"}),
+ ("service.ssh.ciphers.compatibility", {"type": "enum", "default": "modern",
+ "choices": ["intermediate", "modern"]}),
+ ("security.ciphers.compatibility", {"type": "enum", "default": "intermediate",
+ "choices": ["intermediate", "modern"]}),
])
From aaf6dba8d7c28ca43dedc88b0eec907b22ed2629 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 23:03:27 +0100
Subject: [PATCH 036/199] fix yunhost admin config filename
---
data/hooks/conf_regen/15-nginx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx
index 4c5bac331..c33f16cba 100755
--- a/data/hooks/conf_regen/15-nginx
+++ b/data/hooks/conf_regen/15-nginx
@@ -64,7 +64,7 @@ do_pre_regen() {
|| cp yunohost_local.conf "${domain_conf_dir}/yunohost_local.conf"
done
- ynh_render_template "plain/yunohost_admin.conf" "${nginx_conf_dir}/yunohost-admin.conf"
+ ynh_render_template "plain/yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf"
# remove old domain conf files
conf_files=$(ls -1 /etc/nginx/conf.d \
From 5d48640f3c993d5a3d7c80a411531d4efc07892b Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 23:12:59 +0100
Subject: [PATCH 037/199] Adapt comment to new context
---
data/templates/nginx/server.tpl.conf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index e19bab970..84c884055 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -32,7 +32,7 @@ server {
{% if security_ciphers_compatibility == "modern" %}
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
- # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
+ # The following configuration use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
From af82be4ffdc68e5514fda773a750566f3972558f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Sat, 16 Feb 2019 15:43:09 +0100
Subject: [PATCH 038/199] Check if file exist
---
data/helpers.d/system | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index 24e89dccb..71db85390 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -89,14 +89,14 @@ ynh_systemd_action() {
if [[ -n "${line_match:-}" ]]
then
local templog="$(mktemp)"
- # Following the starting of the app in its log
- if [ "$log_path" == "systemd" ] ; then
+ # Following the starting of the app in its log
+ if [ "$log_path" == "systemd" ] ; then
# Read the systemd journal
journalctl --unit=$service_name --follow --since=-0 --quiet > "$templog" &
- else
+ else
# Read the specified log file
tail -F -n0 "$log_path" > "$templog" &
- fi
+ fi
# Get the PID of the tail command
local pid_tail=$!
fi
@@ -104,7 +104,7 @@ ynh_systemd_action() {
echo "${action^} the service $service_name" >&2
systemctl $action $service_name \
|| ( journalctl --lines=$length -u $service_name >&2 \
- ; test -n "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2 \
+ ; test -e "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2 \
; false )
# Start the timeout and try to find line_match
@@ -127,7 +127,7 @@ ynh_systemd_action() {
echo "The service $service_name didn't fully started before the timeout." >&2
echo "Please find here an extract of the end of the log of the service $service_name:"
journalctl --lines=$length -u $service_name >&2
- test -n "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2
+ test -e "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2
fi
echo ""
From 9f3bf11fd06e3d16136e3de9a376c38d3179b956 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Mon, 18 Feb 2019 00:04:55 +0100
Subject: [PATCH 039/199] Add warning about --line_match usage
---
data/helpers.d/system | 3 +++
1 file changed, 3 insertions(+)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index 71db85390..d63a4b482 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -63,6 +63,9 @@ ynh_get_debian_release () {
# | arg: -a, --action= - Action to perform with systemctl. Default: start
# | arg: -l, --line_match= - Line to match - The line to find in the log to attest the service have finished to boot.
# If not defined it don't wait until the service is completely started.
+# WARNING: When using --line_match, you should always add `ynh_clean_check_starting` into your
+# `ynh_clean_setup` at the beginning of the script. Otherwise, tail will not stop in case of failure
+# of the script. The script will then hang forever.
# | arg: -p, --log_path= - Log file - Path to the log file. Default : /var/log/$app/$app.log
# | arg: -t, --timeout= - Timeout - The maximum time to wait before ending the watching. Default : 300 seconds.
# | arg: -e, --length= - Length of the error log : Default : 20
From 9052bb0b78acc46327ba524ac8010b8ad3fc9133 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Mon, 18 Feb 2019 00:11:04 +0100
Subject: [PATCH 040/199] Do not pipe into less
---
data/helpers.d/system | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index d63a4b482..58bc77582 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -106,7 +106,7 @@ ynh_systemd_action() {
echo "${action^} the service $service_name" >&2
systemctl $action $service_name \
- || ( journalctl --lines=$length -u $service_name >&2 \
+ || ( journalctl --no-pager --lines=$length -u $service_name >&2 \
; test -e "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2 \
; false )
@@ -129,7 +129,7 @@ ynh_systemd_action() {
then
echo "The service $service_name didn't fully started before the timeout." >&2
echo "Please find here an extract of the end of the log of the service $service_name:"
- journalctl --lines=$length -u $service_name >&2
+ journalctl --no-pager --lines=$length -u $service_name >&2
test -e "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2
fi
From 631ca4763664dde1c517fd21dbcc94abafc95599 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Mon, 18 Feb 2019 00:12:01 +0100
Subject: [PATCH 041/199] Be sure to get the correct PID
---
data/helpers.d/system | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index 58bc77582..a846ee590 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -96,12 +96,14 @@ ynh_systemd_action() {
if [ "$log_path" == "systemd" ] ; then
# Read the systemd journal
journalctl --unit=$service_name --follow --since=-0 --quiet > "$templog" &
+ # Get the PID of the journalctl command
+ local pid_tail=$!
else
# Read the specified log file
tail -F -n0 "$log_path" > "$templog" &
+ # Get the PID of the tail command
+ local pid_tail=$!
fi
- # Get the PID of the tail command
- local pid_tail=$!
fi
echo "${action^} the service $service_name" >&2
From 42b41aa934c8ca88c21795d4976d690c463cf9a1 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Thu, 7 Feb 2019 17:00:46 +0100
Subject: [PATCH 042/199] Add new regen-conf API in tools category
---
data/actionsmap/yunohost.yml | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml
index cbe959b55..fabdcb923 100644
--- a/data/actionsmap/yunohost.yml
+++ b/data/actionsmap/yunohost.yml
@@ -1623,6 +1623,32 @@ tools:
full: --force
action: store_true
+ ### tools_regen_conf()
+ regen-conf:
+ action_help: Regenerate the configuration file(s)
+ api: PUT /tools/regenconf
+ arguments:
+ names:
+ help: Categories to regenerate configuration of (all by default)
+ nargs: "*"
+ metavar: NAME
+ -d:
+ full: --with-diff
+ help: Show differences in case of configuration changes
+ action: store_true
+ -f:
+ full: --force
+ help: Override all manual modifications in configuration files
+ action: store_true
+ -n:
+ full: --dry-run
+ help: Show what would have been regenerated
+ action: store_true
+ -p:
+ full: --list-pending
+ help: List pending configuration files and exit
+ action: store_true
+
subcategories:
migrations:
From 739bf8e559af5e52cc0c55bf614d649b8737c7ee Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Thu, 7 Feb 2019 17:23:44 +0100
Subject: [PATCH 043/199] Brutally move regenconf stuff to a new regenconf.py
file
---
src/yunohost/regenconf.py | 546 ++++++++++++++++++++++++++++++++++++++
src/yunohost/service.py | 475 ---------------------------------
2 files changed, 546 insertions(+), 475 deletions(-)
create mode 100644 src/yunohost/regenconf.py
diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py
new file mode 100644
index 000000000..0330db508
--- /dev/null
+++ b/src/yunohost/regenconf.py
@@ -0,0 +1,546 @@
+# -*- coding: utf-8 -*-
+
+""" License
+
+ Copyright (C) 2019 YunoHost
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, see http://www.gnu.org/licenses
+
+"""
+
+import os
+import yaml
+import json
+import subprocess
+import shutil
+import hashlib
+
+from difflib import unified_diff
+from datetime import datetime
+
+from moulinette import m18n
+from moulinette.utils import log, filesystem
+
+from yunohost.utils.error import YunohostError
+from yunohost.log import is_unit_operation
+from yunohost.hook import hook_callback, hook_list
+
+BASE_CONF_PATH = '/home/yunohost.conf'
+BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup')
+PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, 'pending')
+
+logger = log.getActionLogger('yunohost.regenconf')
+
+
+@is_unit_operation([('names', 'service')])
+def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run=False,
+ list_pending=False):
+ """
+ Regenerate the configuration file(s) for a service
+
+ Keyword argument:
+ names -- Services name to regenerate configuration of
+ with_diff -- Show differences in case of configuration changes
+ force -- Override all manual modifications in configuration files
+ dry_run -- Show what would have been regenerated
+ list_pending -- List pending configuration files and exit
+
+ """
+ result = {}
+
+ # Return the list of pending conf
+ if list_pending:
+ pending_conf = _get_pending_conf(names)
+
+ if not with_diff:
+ return pending_conf
+
+ for service, conf_files in pending_conf.items():
+ for system_path, pending_path in conf_files.items():
+
+ pending_conf[service][system_path] = {
+ 'pending_conf': pending_path,
+ 'diff': _get_files_diff(
+ system_path, pending_path, True),
+ }
+
+ return pending_conf
+
+ if not dry_run:
+ operation_logger.related_to = [('service', x) for x in names]
+ if not names:
+ operation_logger.name_parameter_override = 'all'
+ elif len(names) != 1:
+ operation_logger.name_parameter_override = str(len(operation_logger.related_to)) + '_services'
+ operation_logger.start()
+
+ # Clean pending conf directory
+ if os.path.isdir(PENDING_CONF_DIR):
+ if not names:
+ shutil.rmtree(PENDING_CONF_DIR, ignore_errors=True)
+ else:
+ for name in names:
+ shutil.rmtree(os.path.join(PENDING_CONF_DIR, name),
+ ignore_errors=True)
+ else:
+ filesystem.mkdir(PENDING_CONF_DIR, 0o755, True)
+
+ # Format common hooks arguments
+ common_args = [1 if force else 0, 1 if dry_run else 0]
+
+ # Execute hooks for pre-regen
+ pre_args = ['pre', ] + common_args
+
+ def _pre_call(name, priority, path, args):
+ # create the pending conf directory for the service
+ service_pending_path = os.path.join(PENDING_CONF_DIR, name)
+ filesystem.mkdir(service_pending_path, 0o755, True, uid='root')
+
+ # return the arguments to pass to the script
+ return pre_args + [service_pending_path, ]
+
+ # Don't regen SSH if not specifically specified
+ if not names:
+ names = hook_list('conf_regen', list_by='name',
+ show_info=False)['hooks']
+ names.remove('ssh')
+
+ pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call)
+
+ # Update the services name
+ names = pre_result['succeed'].keys()
+
+ if not names:
+ raise YunohostError('service_regenconf_failed',
+ services=', '.join(pre_result['failed']))
+
+ # Set the processing method
+ _regen = _process_regen_conf if not dry_run else lambda *a, **k: True
+
+ operation_logger.related_to = []
+
+ # Iterate over services and process pending conf
+ for service, conf_files in _get_pending_conf(names).items():
+ if not dry_run:
+ operation_logger.related_to.append(('service', service))
+
+ logger.debug(m18n.n(
+ 'service_regenconf_pending_applying' if not dry_run else
+ 'service_regenconf_dry_pending_applying',
+ service=service))
+
+ conf_hashes = _get_conf_hashes(service)
+ succeed_regen = {}
+ failed_regen = {}
+
+ for system_path, pending_path in conf_files.items():
+ logger.debug("processing pending conf '%s' to system conf '%s'",
+ pending_path, system_path)
+ conf_status = None
+ regenerated = False
+
+ # Get the diff between files
+ conf_diff = _get_files_diff(
+ system_path, pending_path, True) if with_diff else None
+
+ # Check if the conf must be removed
+ to_remove = True if os.path.getsize(pending_path) == 0 else False
+
+ # Retrieve and calculate hashes
+ system_hash = _calculate_hash(system_path)
+ saved_hash = conf_hashes.get(system_path, None)
+ new_hash = None if to_remove else _calculate_hash(pending_path)
+
+ # -> system conf does not exists
+ if not system_hash:
+ if to_remove:
+ logger.debug("> system conf is already removed")
+ os.remove(pending_path)
+ continue
+ if not saved_hash or force:
+ if force:
+ logger.debug("> system conf has been manually removed")
+ conf_status = 'force-created'
+ else:
+ logger.debug("> system conf does not exist yet")
+ conf_status = 'created'
+ regenerated = _regen(
+ system_path, pending_path, save=False)
+ else:
+ logger.info(m18n.n(
+ 'service_conf_file_manually_removed',
+ conf=system_path))
+ conf_status = 'removed'
+
+ # -> system conf is not managed yet
+ elif not saved_hash:
+ logger.debug("> system conf is not managed yet")
+ if system_hash == new_hash:
+ logger.debug("> no changes to system conf has been made")
+ conf_status = 'managed'
+ regenerated = True
+ elif not to_remove:
+ # If the conf exist but is not managed yet, and is not to be removed,
+ # we assume that it is safe to regen it, since the file is backuped
+ # anyway (by default in _regen), as long as we warn the user
+ # appropriately.
+ logger.info(m18n.n('service_conf_now_managed_by_yunohost',
+ conf=system_path))
+ regenerated = _regen(system_path, pending_path)
+ conf_status = 'new'
+ elif force:
+ regenerated = _regen(system_path)
+ conf_status = 'force-removed'
+ else:
+ logger.info(m18n.n('service_conf_file_kept_back',
+ conf=system_path, service=service))
+ conf_status = 'unmanaged'
+
+ # -> system conf has not been manually modified
+ elif system_hash == saved_hash:
+ if to_remove:
+ regenerated = _regen(system_path)
+ conf_status = 'removed'
+ elif system_hash != new_hash:
+ regenerated = _regen(system_path, pending_path)
+ conf_status = 'updated'
+ else:
+ logger.debug("> system conf is already up-to-date")
+ os.remove(pending_path)
+ continue
+
+ else:
+ logger.debug("> system conf has been manually modified")
+ if system_hash == new_hash:
+ logger.debug("> new conf is as current system conf")
+ conf_status = 'managed'
+ regenerated = True
+ elif force:
+ regenerated = _regen(system_path, pending_path)
+ conf_status = 'force-updated'
+ else:
+ logger.warning(m18n.n(
+ 'service_conf_file_manually_modified',
+ conf=system_path))
+ conf_status = 'modified'
+
+ # Store the result
+ conf_result = {'status': conf_status}
+ if conf_diff is not None:
+ conf_result['diff'] = conf_diff
+ if regenerated:
+ succeed_regen[system_path] = conf_result
+ conf_hashes[system_path] = new_hash
+ if os.path.isfile(pending_path):
+ os.remove(pending_path)
+ else:
+ failed_regen[system_path] = conf_result
+
+ # Check for service conf changes
+ if not succeed_regen and not failed_regen:
+ logger.debug(m18n.n('service_conf_up_to_date', service=service))
+ continue
+ elif not failed_regen:
+ logger.success(m18n.n(
+ 'service_conf_updated' if not dry_run else
+ 'service_conf_would_be_updated',
+ service=service))
+
+ if succeed_regen and not dry_run:
+ _update_conf_hashes(service, conf_hashes)
+
+ # Append the service results
+ result[service] = {
+ 'applied': succeed_regen,
+ 'pending': failed_regen
+ }
+
+ # Return in case of dry run
+ if dry_run:
+ return result
+
+ # Execute hooks for post-regen
+ post_args = ['post', ] + common_args
+
+ def _pre_call(name, priority, path, args):
+ # append coma-separated applied changes for the service
+ if name in result and result[name]['applied']:
+ regen_conf_files = ','.join(result[name]['applied'].keys())
+ else:
+ regen_conf_files = ''
+ return post_args + [regen_conf_files, ]
+
+ hook_callback('conf_regen', names, pre_callback=_pre_call)
+
+ operation_logger.success()
+
+ return result
+
+
+def _get_services():
+ """
+ Get a dict of managed services with their parameters
+
+ """
+ try:
+ with open('/etc/yunohost/services.yml', 'r') as f:
+ services = yaml.load(f)
+ except:
+ return {}
+ else:
+ # some services are marked as None to remove them from YunoHost
+ # filter this
+ for key, value in services.items():
+ if value is None:
+ del services[key]
+
+ return services
+
+
+def _save_services(services):
+ """
+ Save managed services to files
+
+ Keyword argument:
+ services -- A dict of managed services with their parameters
+
+ """
+ try:
+ with open('/etc/yunohost/services.yml', 'w') as f:
+ yaml.safe_dump(services, f, default_flow_style=False)
+ except Exception as e:
+ logger.warning('Error while saving services, exception: %s', e, exc_info=1)
+ raise
+
+
+def _get_files_diff(orig_file, new_file, as_string=False, skip_header=True):
+ """Compare two files and return the differences
+
+ Read and compare two files. The differences are returned either as a delta
+ in unified diff format or a formatted string if as_string is True. The
+ header can also be removed if skip_header is True.
+
+ """
+
+ if os.path.exists(orig_file):
+ with open(orig_file, 'r') as orig_file:
+ orig_file = orig_file.readlines()
+ else:
+ orig_file = []
+
+ if os.path.exists(new_file):
+ with open(new_file, 'r') as new_file:
+ new_file = new_file.readlines()
+ else:
+ new_file = []
+
+ # Compare files and format output
+ diff = unified_diff(orig_file, new_file)
+
+ if skip_header:
+ try:
+ next(diff)
+ next(diff)
+ except:
+ pass
+
+ if as_string:
+ return ''.join(diff).rstrip()
+
+ return diff
+
+
+def _calculate_hash(path):
+ """Calculate the MD5 hash of a file"""
+
+ if not os.path.exists(path):
+ return None
+
+ hasher = hashlib.md5()
+
+ try:
+ with open(path, 'rb') as f:
+ hasher.update(f.read())
+ return hasher.hexdigest()
+
+ except IOError as e:
+ logger.warning("Error while calculating file '%s' hash: %s", path, e, exc_info=1)
+ return None
+
+
+def _get_pending_conf(services=[]):
+ """Get pending configuration for service(s)
+
+ Iterate over the pending configuration directory for given service(s) - or
+ all if empty - and look for files inside. Each file is considered as a
+ pending configuration file and therefore must be in the same directory
+ tree than the system file that it replaces.
+ The result is returned as a dict of services with pending configuration as
+ key and a dict of `system_conf_path` => `pending_conf_path` as value.
+
+ """
+ result = {}
+
+ if not os.path.isdir(PENDING_CONF_DIR):
+ return result
+
+ if not services:
+ services = os.listdir(PENDING_CONF_DIR)
+
+ for name in services:
+ service_pending_path = os.path.join(PENDING_CONF_DIR, name)
+
+ if not os.path.isdir(service_pending_path):
+ continue
+
+ path_index = len(service_pending_path)
+ service_conf = {}
+
+ for root, dirs, files in os.walk(service_pending_path):
+ for filename in files:
+ pending_path = os.path.join(root, filename)
+ service_conf[pending_path[path_index:]] = pending_path
+
+ if service_conf:
+ result[name] = service_conf
+ else:
+ # remove empty directory
+ shutil.rmtree(service_pending_path, ignore_errors=True)
+
+ return result
+
+
+def _get_conf_hashes(service):
+ """Get the registered conf hashes for a service"""
+
+ services = _get_services()
+
+ if service not in services:
+ logger.debug("Service %s is not in services.yml yet.", service)
+ return {}
+
+ elif services[service] is None or 'conffiles' not in services[service]:
+ logger.debug("No configuration files for service %s.", service)
+ return {}
+
+ else:
+ return services[service]['conffiles']
+
+
+def _update_conf_hashes(service, hashes):
+ """Update the registered conf hashes for a service"""
+ logger.debug("updating conf hashes for '%s' with: %s",
+ service, hashes)
+ services = _get_services()
+ service_conf = services.get(service, {})
+
+ # Handle the case where services[service] is set to null in the yaml
+ if service_conf is None:
+ service_conf = {}
+
+ service_conf['conffiles'] = hashes
+ services[service] = service_conf
+ _save_services(services)
+
+
+def _process_regen_conf(system_conf, new_conf=None, save=True):
+ """Regenerate a given system configuration file
+
+ Replace a given system configuration file by a new one or delete it if
+ new_conf is None. A backup of the file - keeping its directory tree - will
+ be done in the backup conf directory before any operation if save is True.
+
+ """
+ if save:
+ backup_path = os.path.join(BACKUP_CONF_DIR, '{0}-{1}'.format(
+ system_conf.lstrip('/'), datetime.utcnow().strftime("%Y%m%d.%H%M%S")))
+ backup_dir = os.path.dirname(backup_path)
+
+ if not os.path.isdir(backup_dir):
+ filesystem.mkdir(backup_dir, 0o755, True)
+
+ shutil.copy2(system_conf, backup_path)
+ logger.debug(m18n.n('service_conf_file_backed_up',
+ conf=system_conf, backup=backup_path))
+
+ try:
+ if not new_conf:
+ os.remove(system_conf)
+ logger.debug(m18n.n('service_conf_file_removed',
+ conf=system_conf))
+ else:
+ system_dir = os.path.dirname(system_conf)
+
+ if not os.path.isdir(system_dir):
+ filesystem.mkdir(system_dir, 0o755, True)
+
+ shutil.copyfile(new_conf, system_conf)
+ logger.debug(m18n.n('service_conf_file_updated',
+ conf=system_conf))
+ except Exception as e:
+ logger.warning("Exception while trying to regenerate conf '%s': %s", system_conf, e, exc_info=1)
+ if not new_conf and os.path.exists(system_conf):
+ logger.warning(m18n.n('service_conf_file_remove_failed',
+ conf=system_conf),
+ exc_info=1)
+ return False
+
+ elif new_conf:
+ try:
+ # From documentation:
+ # Raise an exception if an os.stat() call on either pathname fails.
+ # (os.stats returns a series of information from a file like type, size...)
+ copy_succeed = os.path.samefile(system_conf, new_conf)
+ except:
+ copy_succeed = False
+ finally:
+ if not copy_succeed:
+ logger.warning(m18n.n('service_conf_file_copy_failed',
+ conf=system_conf, new=new_conf),
+ exc_info=1)
+ return False
+
+ return True
+
+
+def manually_modified_files():
+
+ # We do this to have --quiet, i.e. don't throw a whole bunch of logs
+ # just to fetch this...
+ # Might be able to optimize this by looking at what service_regenconf does
+ # and only do the part that checks file hashes...
+ cmd = "yunohost service regen-conf --dry-run --output-as json --quiet"
+ j = json.loads(subprocess.check_output(cmd.split()))
+
+ # j is something like :
+ # {"postfix": {"applied": {}, "pending": {"/etc/postfix/main.cf": {"status": "modified"}}}
+
+ output = []
+ for app, actions in j.items():
+ for action, files in actions.items():
+ for filename, infos in files.items():
+ if infos["status"] == "modified":
+ output.append(filename)
+
+ return output
+
+
+def manually_modified_files_compared_to_debian_default():
+
+ # from https://serverfault.com/a/90401
+ r = subprocess.check_output("dpkg-query -W -f='${Conffiles}\n' '*' \
+ | awk 'OFS=\" \"{print $2,$1}' \
+ | md5sum -c 2>/dev/null \
+ | awk -F': ' '$2 !~ /OK/{print $1}'", shell=True)
+ return r.strip().split("\n")
diff --git a/src/yunohost/service.py b/src/yunohost/service.py
index 60729053b..ab0e791d8 100644
--- a/src/yunohost/service.py
+++ b/src/yunohost/service.py
@@ -26,12 +26,8 @@
import os
import time
import yaml
-import json
import subprocess
-import shutil
-import hashlib
-from difflib import unified_diff
from datetime import datetime
from moulinette import m18n
@@ -39,11 +35,7 @@ from yunohost.utils.error import YunohostError
from moulinette.utils import log, filesystem
from yunohost.log import is_unit_operation
-from yunohost.hook import hook_callback, hook_list
-BASE_CONF_PATH = '/home/yunohost.conf'
-BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup')
-PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, 'pending')
MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock"
logger = log.getActionLogger('yunohost.service')
@@ -418,251 +410,6 @@ def service_log(name, number=50):
return result
-@is_unit_operation([('names', 'service')])
-def service_regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run=False,
- list_pending=False):
- """
- Regenerate the configuration file(s) for a service
-
- Keyword argument:
- names -- Services name to regenerate configuration of
- with_diff -- Show differences in case of configuration changes
- force -- Override all manual modifications in configuration files
- dry_run -- Show what would have been regenerated
- list_pending -- List pending configuration files and exit
-
- """
- result = {}
-
- # Return the list of pending conf
- if list_pending:
- pending_conf = _get_pending_conf(names)
-
- if not with_diff:
- return pending_conf
-
- for service, conf_files in pending_conf.items():
- for system_path, pending_path in conf_files.items():
-
- pending_conf[service][system_path] = {
- 'pending_conf': pending_path,
- 'diff': _get_files_diff(
- system_path, pending_path, True),
- }
-
- return pending_conf
-
- if not dry_run:
- operation_logger.related_to = [('service', x) for x in names]
- if not names:
- operation_logger.name_parameter_override = 'all'
- elif len(names) != 1:
- operation_logger.name_parameter_override = str(len(operation_logger.related_to)) + '_services'
- operation_logger.start()
-
- # Clean pending conf directory
- if os.path.isdir(PENDING_CONF_DIR):
- if not names:
- shutil.rmtree(PENDING_CONF_DIR, ignore_errors=True)
- else:
- for name in names:
- shutil.rmtree(os.path.join(PENDING_CONF_DIR, name),
- ignore_errors=True)
- else:
- filesystem.mkdir(PENDING_CONF_DIR, 0o755, True)
-
- # Format common hooks arguments
- common_args = [1 if force else 0, 1 if dry_run else 0]
-
- # Execute hooks for pre-regen
- pre_args = ['pre', ] + common_args
-
- def _pre_call(name, priority, path, args):
- # create the pending conf directory for the service
- service_pending_path = os.path.join(PENDING_CONF_DIR, name)
- filesystem.mkdir(service_pending_path, 0o755, True, uid='root')
-
- # return the arguments to pass to the script
- return pre_args + [service_pending_path, ]
-
- # Don't regen SSH if not specifically specified
- if not names:
- names = hook_list('conf_regen', list_by='name',
- show_info=False)['hooks']
- names.remove('ssh')
-
- pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call)
-
- # Update the services name
- names = pre_result['succeed'].keys()
-
- if not names:
- raise YunohostError('service_regenconf_failed',
- services=', '.join(pre_result['failed']))
-
- # Set the processing method
- _regen = _process_regen_conf if not dry_run else lambda *a, **k: True
-
- operation_logger.related_to = []
-
- # Iterate over services and process pending conf
- for service, conf_files in _get_pending_conf(names).items():
- if not dry_run:
- operation_logger.related_to.append(('service', service))
-
- logger.debug(m18n.n(
- 'service_regenconf_pending_applying' if not dry_run else
- 'service_regenconf_dry_pending_applying',
- service=service))
-
- conf_hashes = _get_conf_hashes(service)
- succeed_regen = {}
- failed_regen = {}
-
- for system_path, pending_path in conf_files.items():
- logger.debug("processing pending conf '%s' to system conf '%s'",
- pending_path, system_path)
- conf_status = None
- regenerated = False
-
- # Get the diff between files
- conf_diff = _get_files_diff(
- system_path, pending_path, True) if with_diff else None
-
- # Check if the conf must be removed
- to_remove = True if os.path.getsize(pending_path) == 0 else False
-
- # Retrieve and calculate hashes
- system_hash = _calculate_hash(system_path)
- saved_hash = conf_hashes.get(system_path, None)
- new_hash = None if to_remove else _calculate_hash(pending_path)
-
- # -> system conf does not exists
- if not system_hash:
- if to_remove:
- logger.debug("> system conf is already removed")
- os.remove(pending_path)
- continue
- if not saved_hash or force:
- if force:
- logger.debug("> system conf has been manually removed")
- conf_status = 'force-created'
- else:
- logger.debug("> system conf does not exist yet")
- conf_status = 'created'
- regenerated = _regen(
- system_path, pending_path, save=False)
- else:
- logger.info(m18n.n(
- 'service_conf_file_manually_removed',
- conf=system_path))
- conf_status = 'removed'
-
- # -> system conf is not managed yet
- elif not saved_hash:
- logger.debug("> system conf is not managed yet")
- if system_hash == new_hash:
- logger.debug("> no changes to system conf has been made")
- conf_status = 'managed'
- regenerated = True
- elif not to_remove:
- # If the conf exist but is not managed yet, and is not to be removed,
- # we assume that it is safe to regen it, since the file is backuped
- # anyway (by default in _regen), as long as we warn the user
- # appropriately.
- logger.info(m18n.n('service_conf_now_managed_by_yunohost',
- conf=system_path))
- regenerated = _regen(system_path, pending_path)
- conf_status = 'new'
- elif force:
- regenerated = _regen(system_path)
- conf_status = 'force-removed'
- else:
- logger.info(m18n.n('service_conf_file_kept_back',
- conf=system_path, service=service))
- conf_status = 'unmanaged'
-
- # -> system conf has not been manually modified
- elif system_hash == saved_hash:
- if to_remove:
- regenerated = _regen(system_path)
- conf_status = 'removed'
- elif system_hash != new_hash:
- regenerated = _regen(system_path, pending_path)
- conf_status = 'updated'
- else:
- logger.debug("> system conf is already up-to-date")
- os.remove(pending_path)
- continue
-
- else:
- logger.debug("> system conf has been manually modified")
- if system_hash == new_hash:
- logger.debug("> new conf is as current system conf")
- conf_status = 'managed'
- regenerated = True
- elif force:
- regenerated = _regen(system_path, pending_path)
- conf_status = 'force-updated'
- else:
- logger.warning(m18n.n(
- 'service_conf_file_manually_modified',
- conf=system_path))
- conf_status = 'modified'
-
- # Store the result
- conf_result = {'status': conf_status}
- if conf_diff is not None:
- conf_result['diff'] = conf_diff
- if regenerated:
- succeed_regen[system_path] = conf_result
- conf_hashes[system_path] = new_hash
- if os.path.isfile(pending_path):
- os.remove(pending_path)
- else:
- failed_regen[system_path] = conf_result
-
- # Check for service conf changes
- if not succeed_regen and not failed_regen:
- logger.debug(m18n.n('service_conf_up_to_date', service=service))
- continue
- elif not failed_regen:
- logger.success(m18n.n(
- 'service_conf_updated' if not dry_run else
- 'service_conf_would_be_updated',
- service=service))
-
- if succeed_regen and not dry_run:
- _update_conf_hashes(service, conf_hashes)
-
- # Append the service results
- result[service] = {
- 'applied': succeed_regen,
- 'pending': failed_regen
- }
-
- # Return in case of dry run
- if dry_run:
- return result
-
- # Execute hooks for post-regen
- post_args = ['post', ] + common_args
-
- def _pre_call(name, priority, path, args):
- # append coma-separated applied changes for the service
- if name in result and result[name]['applied']:
- regen_conf_files = ','.join(result[name]['applied'].keys())
- else:
- regen_conf_files = ''
- return post_args + [regen_conf_files, ]
-
- hook_callback('conf_regen', names, pre_callback=_pre_call)
-
- operation_logger.success()
-
- return result
-
-
def _run_service_command(action, service):
"""
Run services management command (start, stop, enable, disable, restart, reload)
@@ -860,231 +607,9 @@ def _find_previous_log_file(file):
return None
-def _get_files_diff(orig_file, new_file, as_string=False, skip_header=True):
- """Compare two files and return the differences
-
- Read and compare two files. The differences are returned either as a delta
- in unified diff format or a formatted string if as_string is True. The
- header can also be removed if skip_header is True.
-
- """
-
- if os.path.exists(orig_file):
- with open(orig_file, 'r') as orig_file:
- orig_file = orig_file.readlines()
- else:
- orig_file = []
-
- if os.path.exists(new_file):
- with open(new_file, 'r') as new_file:
- new_file = new_file.readlines()
- else:
- new_file = []
-
- # Compare files and format output
- diff = unified_diff(orig_file, new_file)
-
- if skip_header:
- try:
- next(diff)
- next(diff)
- except:
- pass
-
- if as_string:
- return ''.join(diff).rstrip()
-
- return diff
-
-
-def _calculate_hash(path):
- """Calculate the MD5 hash of a file"""
-
- if not os.path.exists(path):
- return None
-
- hasher = hashlib.md5()
-
- try:
- with open(path, 'rb') as f:
- hasher.update(f.read())
- return hasher.hexdigest()
-
- except IOError as e:
- logger.warning("Error while calculating file '%s' hash: %s", path, e, exc_info=1)
- return None
-
-
-def _get_pending_conf(services=[]):
- """Get pending configuration for service(s)
-
- Iterate over the pending configuration directory for given service(s) - or
- all if empty - and look for files inside. Each file is considered as a
- pending configuration file and therefore must be in the same directory
- tree than the system file that it replaces.
- The result is returned as a dict of services with pending configuration as
- key and a dict of `system_conf_path` => `pending_conf_path` as value.
-
- """
- result = {}
-
- if not os.path.isdir(PENDING_CONF_DIR):
- return result
-
- if not services:
- services = os.listdir(PENDING_CONF_DIR)
-
- for name in services:
- service_pending_path = os.path.join(PENDING_CONF_DIR, name)
-
- if not os.path.isdir(service_pending_path):
- continue
-
- path_index = len(service_pending_path)
- service_conf = {}
-
- for root, dirs, files in os.walk(service_pending_path):
- for filename in files:
- pending_path = os.path.join(root, filename)
- service_conf[pending_path[path_index:]] = pending_path
-
- if service_conf:
- result[name] = service_conf
- else:
- # remove empty directory
- shutil.rmtree(service_pending_path, ignore_errors=True)
-
- return result
-
-
-def _get_conf_hashes(service):
- """Get the registered conf hashes for a service"""
-
- services = _get_services()
-
- if service not in services:
- logger.debug("Service %s is not in services.yml yet.", service)
- return {}
-
- elif services[service] is None or 'conffiles' not in services[service]:
- logger.debug("No configuration files for service %s.", service)
- return {}
-
- else:
- return services[service]['conffiles']
-
-
-def _update_conf_hashes(service, hashes):
- """Update the registered conf hashes for a service"""
- logger.debug("updating conf hashes for '%s' with: %s",
- service, hashes)
- services = _get_services()
- service_conf = services.get(service, {})
-
- # Handle the case where services[service] is set to null in the yaml
- if service_conf is None:
- service_conf = {}
-
- service_conf['conffiles'] = hashes
- services[service] = service_conf
- _save_services(services)
-
-
-def _process_regen_conf(system_conf, new_conf=None, save=True):
- """Regenerate a given system configuration file
-
- Replace a given system configuration file by a new one or delete it if
- new_conf is None. A backup of the file - keeping its directory tree - will
- be done in the backup conf directory before any operation if save is True.
-
- """
- if save:
- backup_path = os.path.join(BACKUP_CONF_DIR, '{0}-{1}'.format(
- system_conf.lstrip('/'), datetime.utcnow().strftime("%Y%m%d.%H%M%S")))
- backup_dir = os.path.dirname(backup_path)
-
- if not os.path.isdir(backup_dir):
- filesystem.mkdir(backup_dir, 0o755, True)
-
- shutil.copy2(system_conf, backup_path)
- logger.debug(m18n.n('service_conf_file_backed_up',
- conf=system_conf, backup=backup_path))
-
- try:
- if not new_conf:
- os.remove(system_conf)
- logger.debug(m18n.n('service_conf_file_removed',
- conf=system_conf))
- else:
- system_dir = os.path.dirname(system_conf)
-
- if not os.path.isdir(system_dir):
- filesystem.mkdir(system_dir, 0o755, True)
-
- shutil.copyfile(new_conf, system_conf)
- logger.debug(m18n.n('service_conf_file_updated',
- conf=system_conf))
- except Exception as e:
- logger.warning("Exception while trying to regenerate conf '%s': %s", system_conf, e, exc_info=1)
- if not new_conf and os.path.exists(system_conf):
- logger.warning(m18n.n('service_conf_file_remove_failed',
- conf=system_conf),
- exc_info=1)
- return False
-
- elif new_conf:
- try:
- # From documentation:
- # Raise an exception if an os.stat() call on either pathname fails.
- # (os.stats returns a series of information from a file like type, size...)
- copy_succeed = os.path.samefile(system_conf, new_conf)
- except:
- copy_succeed = False
- finally:
- if not copy_succeed:
- logger.warning(m18n.n('service_conf_file_copy_failed',
- conf=system_conf, new=new_conf),
- exc_info=1)
- return False
-
- return True
-
-
-def manually_modified_files():
-
- # We do this to have --quiet, i.e. don't throw a whole bunch of logs
- # just to fetch this...
- # Might be able to optimize this by looking at what service_regenconf does
- # and only do the part that checks file hashes...
- cmd = "yunohost service regen-conf --dry-run --output-as json --quiet"
- j = json.loads(subprocess.check_output(cmd.split()))
-
- # j is something like :
- # {"postfix": {"applied": {}, "pending": {"/etc/postfix/main.cf": {"status": "modified"}}}
-
- output = []
- for app, actions in j.items():
- for action, files in actions.items():
- for filename, infos in files.items():
- if infos["status"] == "modified":
- output.append(filename)
-
- return output
-
-
def _get_journalctl_logs(service, number="all"):
try:
return subprocess.check_output("journalctl -xn -u {0} -n{1}".format(service, number), shell=True)
except:
import traceback
return "error while get services logs from journalctl:\n%s" % traceback.format_exc()
-
-
-def manually_modified_files_compared_to_debian_default():
-
- # from https://serverfault.com/a/90401
- r = subprocess.check_output("dpkg-query -W -f='${Conffiles}\n' '*' \
- | awk 'OFS=\" \"{print $2,$1}' \
- | md5sum -c 2>/dev/null \
- | awk -F': ' '$2 !~ /OK/{print $1}'", shell=True)
- return r.strip().split("\n")
From 3067e8e8975e77a3309a3038e0ba614647a381b6 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 8 Feb 2019 12:03:17 +0100
Subject: [PATCH 044/199] Misc renaming for consistency, basically
service->category
---
locales/en.json | 30 ++++----
src/yunohost/regenconf.py | 152 +++++++++++++++++++-------------------
2 files changed, 92 insertions(+), 90 deletions(-)
diff --git a/locales/en.json b/locales/en.json
index 8528c2576..34517a036 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -377,6 +377,21 @@
"port_available": "Port {port:d} is available",
"port_unavailable": "Port {port:d} is not available",
"recommend_to_add_first_user": "The post-install is finished but YunoHost needs at least one user to work correctly, you should add one using 'yunohost user create' or the admin interface.",
+ "regenconf_file_backed_up": "The configuration file '{conf}' has been backed up to '{backup}'",
+ "regenconf_file_copy_failed": "Unable to copy the new configuration file '{new}' to '{conf}'",
+ "regenconf_file_kept_back": "The configuration file '{conf}' is expected to be deleted by regen-conf (category {category}) but has been kept back.",
+ "regenconf_file_manually_modified": "The configuration file '{conf}' has been manually modified and will not be updated",
+ "regenconf_file_manually_removed": "The configuration file '{conf}' has been manually removed and will not be created",
+ "regenconf_file_remove_failed": "Unable to remove the configuration file '{conf}'",
+ "regenconf_file_removed": "The configuration file '{conf}' has been removed",
+ "regenconf_file_updated": "The configuration file '{conf}' has been updated",
+ "regenconf_now_managed_by_yunohost": "The configuration file '{conf}' is now managed by YunoHost (category {category}).",
+ "regenconf_up_to_date": "The configuration is already up-to-date for category '{category}'",
+ "regenconf_updated": "The configuration has been updated for category '{category}'",
+ "regenconf_would_be_updated": "The configuration would have been updated for category '{category}'",
+ "regenconf_dry_pending_applying": "Checking pending configuration which would have been applied for category '{category}'…",
+ "regenconf_failed": "Unable to regenerate the configuration for category(s): {categories}",
+ "regenconf_pending_applying": "Applying pending configuration for category '{category}'…",
"restore_action_required": "You must specify something to restore",
"restore_already_installed_app": "An app is already installed with the id '{app:s}'",
"restore_app_failed": "Unable to restore the app '{app:s}'",
@@ -405,18 +420,6 @@
"service_already_started": "Service '{service:s}' has already been started",
"service_already_stopped": "Service '{service:s}' has already been stopped",
"service_cmd_exec_failed": "Unable to execute command '{command:s}'",
- "service_conf_file_backed_up": "The configuration file '{conf}' has been backed up to '{backup}'",
- "service_conf_file_copy_failed": "Unable to copy the new configuration file '{new}' to '{conf}'",
- "service_conf_file_kept_back": "The configuration file '{conf}' is expected to be deleted by service {service} but has been kept back.",
- "service_conf_file_manually_modified": "The configuration file '{conf}' has been manually modified and will not be updated",
- "service_conf_file_manually_removed": "The configuration file '{conf}' has been manually removed and will not be created",
- "service_conf_file_remove_failed": "Unable to remove the configuration file '{conf}'",
- "service_conf_file_removed": "The configuration file '{conf}' has been removed",
- "service_conf_file_updated": "The configuration file '{conf}' has been updated",
- "service_conf_now_managed_by_yunohost": "The configuration file '{conf}' is now managed by YunoHost.",
- "service_conf_up_to_date": "The configuration is already up-to-date for service '{service}'",
- "service_conf_updated": "The configuration has been updated for service '{service}'",
- "service_conf_would_be_updated": "The configuration would have been updated for service '{service}'",
"service_description_avahi-daemon": "allows to reach your server using yunohost.local on your local network",
"service_description_dnsmasq": "handles domain name resolution (DNS)",
"service_description_dovecot": "allows e-mail client to access/fetch email (via IMAP and POP3)",
@@ -440,9 +443,6 @@
"service_enable_failed": "Unable to enable service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_enabled": "The service '{service:s}' has been enabled",
"service_no_log": "No log to display for service '{service:s}'",
- "service_regenconf_dry_pending_applying": "Checking pending configuration which would have been applied for service '{service}'…",
- "service_regenconf_failed": "Unable to regenerate the configuration for service(s): {services}",
- "service_regenconf_pending_applying": "Applying pending configuration for service '{service}'…",
"service_remove_failed": "Unable to remove service '{service:s}'",
"service_removed": "The service '{service:s}' has been removed",
"service_reload_failed": "Unable to reload service '{service:s}'\n\nRecent service logs:{logs:s}",
diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py
index 0330db508..4104e2491 100644
--- a/src/yunohost/regenconf.py
+++ b/src/yunohost/regenconf.py
@@ -43,14 +43,16 @@ PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, 'pending')
logger = log.getActionLogger('yunohost.regenconf')
+# FIXME : those ain't just services anymore ... what are we supposed to do with this ...
+# FIXME : check for all reference of 'service' close to operation_logger stuff
@is_unit_operation([('names', 'service')])
def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run=False,
list_pending=False):
"""
- Regenerate the configuration file(s) for a service
+ Regenerate the configuration file(s)
Keyword argument:
- names -- Services name to regenerate configuration of
+ names -- Categories to regenerate configuration of
with_diff -- Show differences in case of configuration changes
force -- Override all manual modifications in configuration files
dry_run -- Show what would have been regenerated
@@ -66,10 +68,10 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
if not with_diff:
return pending_conf
- for service, conf_files in pending_conf.items():
+ for category, conf_files in pending_conf.items():
for system_path, pending_path in conf_files.items():
- pending_conf[service][system_path] = {
+ pending_conf[category][system_path] = {
'pending_conf': pending_path,
'diff': _get_files_diff(
system_path, pending_path, True),
@@ -103,12 +105,12 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
pre_args = ['pre', ] + common_args
def _pre_call(name, priority, path, args):
- # create the pending conf directory for the service
- service_pending_path = os.path.join(PENDING_CONF_DIR, name)
- filesystem.mkdir(service_pending_path, 0o755, True, uid='root')
+ # create the pending conf directory for the category
+ category_pending_path = os.path.join(PENDING_CONF_DIR, name)
+ filesystem.mkdir(category_pending_path, 0o755, True, uid='root')
# return the arguments to pass to the script
- return pre_args + [service_pending_path, ]
+ return pre_args + [category_pending_path, ]
# Don't regen SSH if not specifically specified
if not names:
@@ -118,29 +120,29 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call)
- # Update the services name
+ # Update the categorys name
names = pre_result['succeed'].keys()
if not names:
- raise YunohostError('service_regenconf_failed',
- services=', '.join(pre_result['failed']))
+ raise YunohostError('regenconf_failed',
+ categories=', '.join(pre_result['failed']))
# Set the processing method
_regen = _process_regen_conf if not dry_run else lambda *a, **k: True
operation_logger.related_to = []
- # Iterate over services and process pending conf
- for service, conf_files in _get_pending_conf(names).items():
+ # Iterate over categorys and process pending conf
+ for category, conf_files in _get_pending_conf(names).items():
if not dry_run:
- operation_logger.related_to.append(('service', service))
+ operation_logger.related_to.append(('service', category))
logger.debug(m18n.n(
- 'service_regenconf_pending_applying' if not dry_run else
- 'service_regenconf_dry_pending_applying',
- service=service))
+ 'regenconf_pending_applying' if not dry_run else
+ 'regenconf_dry_pending_applying',
+ category=category))
- conf_hashes = _get_conf_hashes(service)
+ conf_hashes = _get_conf_hashes(category)
succeed_regen = {}
failed_regen = {}
@@ -179,7 +181,7 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
system_path, pending_path, save=False)
else:
logger.info(m18n.n(
- 'service_conf_file_manually_removed',
+ 'regenconf_file_manually_removed',
conf=system_path))
conf_status = 'removed'
@@ -195,16 +197,16 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
# we assume that it is safe to regen it, since the file is backuped
# anyway (by default in _regen), as long as we warn the user
# appropriately.
- logger.info(m18n.n('service_conf_now_managed_by_yunohost',
- conf=system_path))
+ logger.info(m18n.n('regenconf_now_managed_by_yunohost',
+ conf=system_path, category=category))
regenerated = _regen(system_path, pending_path)
conf_status = 'new'
elif force:
regenerated = _regen(system_path)
conf_status = 'force-removed'
else:
- logger.info(m18n.n('service_conf_file_kept_back',
- conf=system_path, service=service))
+ logger.info(m18n.n('regenconf_file_kept_back',
+ conf=system_path, category=category))
conf_status = 'unmanaged'
# -> system conf has not been manually modified
@@ -231,7 +233,7 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
conf_status = 'force-updated'
else:
logger.warning(m18n.n(
- 'service_conf_file_manually_modified',
+ 'regenconf_file_manually_modified',
conf=system_path))
conf_status = 'modified'
@@ -247,21 +249,21 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
else:
failed_regen[system_path] = conf_result
- # Check for service conf changes
+ # Check for category conf changes
if not succeed_regen and not failed_regen:
- logger.debug(m18n.n('service_conf_up_to_date', service=service))
+ logger.debug(m18n.n('regenconf_up_to_date', category=category))
continue
elif not failed_regen:
logger.success(m18n.n(
- 'service_conf_updated' if not dry_run else
- 'service_conf_would_be_updated',
- service=service))
+ 'regenconf_updated' if not dry_run else
+ 'regenconf_would_be_updated',
+ category=category))
if succeed_regen and not dry_run:
- _update_conf_hashes(service, conf_hashes)
+ _update_conf_hashes(category, conf_hashes)
- # Append the service results
- result[service] = {
+ # Append the category results
+ result[category] = {
'applied': succeed_regen,
'pending': failed_regen
}
@@ -274,7 +276,7 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
post_args = ['post', ] + common_args
def _pre_call(name, priority, path, args):
- # append coma-separated applied changes for the service
+ # append coma-separated applied changes for the category
if name in result and result[name]['applied']:
regen_conf_files = ','.join(result[name]['applied'].keys())
else:
@@ -379,14 +381,14 @@ def _calculate_hash(path):
return None
-def _get_pending_conf(services=[]):
- """Get pending configuration for service(s)
+def _get_pending_conf(categories=[]):
+ """Get pending configuration for categories
- Iterate over the pending configuration directory for given service(s) - or
+ Iterate over the pending configuration directory for given categories - or
all if empty - and look for files inside. Each file is considered as a
pending configuration file and therefore must be in the same directory
tree than the system file that it replaces.
- The result is returned as a dict of services with pending configuration as
+ The result is returned as a dict of categories with pending configuration as
key and a dict of `system_conf_path` => `pending_conf_path` as value.
"""
@@ -395,63 +397,63 @@ def _get_pending_conf(services=[]):
if not os.path.isdir(PENDING_CONF_DIR):
return result
- if not services:
- services = os.listdir(PENDING_CONF_DIR)
+ if not categories:
+ categories = os.listdir(PENDING_CONF_DIR)
- for name in services:
- service_pending_path = os.path.join(PENDING_CONF_DIR, name)
+ for name in categories:
+ category_pending_path = os.path.join(PENDING_CONF_DIR, name)
- if not os.path.isdir(service_pending_path):
+ if not os.path.isdir(category_pending_path):
continue
- path_index = len(service_pending_path)
- service_conf = {}
+ path_index = len(category_pending_path)
+ category_conf = {}
- for root, dirs, files in os.walk(service_pending_path):
+ for root, dirs, files in os.walk(category_pending_path):
for filename in files:
pending_path = os.path.join(root, filename)
- service_conf[pending_path[path_index:]] = pending_path
+ category_conf[pending_path[path_index:]] = pending_path
- if service_conf:
- result[name] = service_conf
+ if category_conf:
+ result[name] = category_conf
else:
# remove empty directory
- shutil.rmtree(service_pending_path, ignore_errors=True)
+ shutil.rmtree(category_pending_path, ignore_errors=True)
return result
-def _get_conf_hashes(service):
- """Get the registered conf hashes for a service"""
+def _get_conf_hashes(category):
+ """Get the registered conf hashes for a category"""
- services = _get_services()
+ categories = _get_categories()
- if service not in services:
- logger.debug("Service %s is not in services.yml yet.", service)
+ if category not in categories:
+ logger.debug("category %s is not in categories.yml yet.", category)
return {}
- elif services[service] is None or 'conffiles' not in services[service]:
- logger.debug("No configuration files for service %s.", service)
+ elif categories[category] is None or 'conffiles' not in categories[category]:
+ logger.debug("No configuration files for category %s.", category)
return {}
else:
- return services[service]['conffiles']
+ return categories[category]['conffiles']
-def _update_conf_hashes(service, hashes):
- """Update the registered conf hashes for a service"""
+def _update_conf_hashes(category, hashes):
+ """Update the registered conf hashes for a category"""
logger.debug("updating conf hashes for '%s' with: %s",
- service, hashes)
- services = _get_services()
- service_conf = services.get(service, {})
+ category, hashes)
+ categories = _get_categories()
+ category_conf = categories.get(category, {})
- # Handle the case where services[service] is set to null in the yaml
- if service_conf is None:
- service_conf = {}
+ # Handle the case where categories[category] is set to null in the yaml
+ if category_conf is None:
+ category_conf = {}
- service_conf['conffiles'] = hashes
- services[service] = service_conf
- _save_services(services)
+ category_conf['conffiles'] = hashes
+ categories[category] = category_conf
+ _save_categories(categories)
def _process_regen_conf(system_conf, new_conf=None, save=True):
@@ -471,13 +473,13 @@ def _process_regen_conf(system_conf, new_conf=None, save=True):
filesystem.mkdir(backup_dir, 0o755, True)
shutil.copy2(system_conf, backup_path)
- logger.debug(m18n.n('service_conf_file_backed_up',
+ logger.debug(m18n.n('regenconf_file_backed_up',
conf=system_conf, backup=backup_path))
try:
if not new_conf:
os.remove(system_conf)
- logger.debug(m18n.n('service_conf_file_removed',
+ logger.debug(m18n.n('regenconf_file_removed',
conf=system_conf))
else:
system_dir = os.path.dirname(system_conf)
@@ -486,12 +488,12 @@ def _process_regen_conf(system_conf, new_conf=None, save=True):
filesystem.mkdir(system_dir, 0o755, True)
shutil.copyfile(new_conf, system_conf)
- logger.debug(m18n.n('service_conf_file_updated',
+ logger.debug(m18n.n('regenconf_file_updated',
conf=system_conf))
except Exception as e:
logger.warning("Exception while trying to regenerate conf '%s': %s", system_conf, e, exc_info=1)
if not new_conf and os.path.exists(system_conf):
- logger.warning(m18n.n('service_conf_file_remove_failed',
+ logger.warning(m18n.n('regenconf_file_remove_failed',
conf=system_conf),
exc_info=1)
return False
@@ -506,7 +508,7 @@ def _process_regen_conf(system_conf, new_conf=None, save=True):
copy_succeed = False
finally:
if not copy_succeed:
- logger.warning(m18n.n('service_conf_file_copy_failed',
+ logger.warning(m18n.n('regenconf_file_copy_failed',
conf=system_conf, new=new_conf),
exc_info=1)
return False
@@ -518,9 +520,9 @@ def manually_modified_files():
# We do this to have --quiet, i.e. don't throw a whole bunch of logs
# just to fetch this...
- # Might be able to optimize this by looking at what service_regenconf does
+ # Might be able to optimize this by looking at what the regen conf does
# and only do the part that checks file hashes...
- cmd = "yunohost service regen-conf --dry-run --output-as json --quiet"
+ cmd = "yunohost tools regen-conf --dry-run --output-as json --quiet"
j = json.loads(subprocess.check_output(cmd.split()))
# j is something like :
From e6f3a99269927a17829977dfa9682eb22827eae6 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 17:44:09 +0100
Subject: [PATCH 045/199] Change binding from service_regen_conf to
tools_regen_conf
---
debian/postinst | 2 +-
locales/en.json | 1 +
src/yunohost/backup.py | 4 ++--
src/yunohost/certificate.py | 7 +++---
...0007_ssh_conf_managed_by_yunohost_step1.py | 6 ++---
...0008_ssh_conf_managed_by_yunohost_step2.py | 6 ++---
src/yunohost/domain.py | 6 ++---
src/yunohost/service.py | 13 +++++++++++
src/yunohost/tools.py | 22 ++++++++++++-------
9 files changed, 44 insertions(+), 23 deletions(-)
diff --git a/debian/postinst b/debian/postinst
index df7112b9d..83220ae0b 100644
--- a/debian/postinst
+++ b/debian/postinst
@@ -12,7 +12,7 @@ do_configure() {
bash /usr/share/yunohost/hooks/conf_regen/15-nginx init
else
echo "Regenerating configuration, this might take a while..."
- yunohost service regen-conf --output-as none
+ yunohost tools regen-conf --output-as none
echo "Launching migrations.."
yunohost tools migrations migrate --auto
diff --git a/locales/en.json b/locales/en.json
index 34517a036..5ab2a749b 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -443,6 +443,7 @@
"service_enable_failed": "Unable to enable service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_enabled": "The service '{service:s}' has been enabled",
"service_no_log": "No log to display for service '{service:s}'",
+ "service_regen_conf_is_deprecated": "'yunohost service regen-conf' is depracted! Please use 'yunohost tools regen-conf' instead.",
"service_remove_failed": "Unable to remove service '{service:s}'",
"service_removed": "The service '{service:s}' has been removed",
"service_reload_failed": "Unable to reload service '{service:s}'\n\nRecent service logs:{logs:s}",
diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py
index ed7799fc1..9f48700a2 100644
--- a/src/yunohost/backup.py
+++ b/src/yunohost/backup.py
@@ -50,7 +50,7 @@ from yunohost.hook import (
)
from yunohost.monitor import binary_to_human
from yunohost.tools import tools_postinstall
-from yunohost.service import service_regen_conf
+from yunohost.regenconf import regen_conf
from yunohost.log import OperationLogger
from functools import reduce
@@ -1191,7 +1191,7 @@ class RestoreManager():
else:
operation_logger.success()
- service_regen_conf()
+ regen_conf()
def _restore_apps(self):
"""Restore all apps targeted"""
diff --git a/src/yunohost/certificate.py b/src/yunohost/certificate.py
index 855910b8a..d7e8c0157 100644
--- a/src/yunohost/certificate.py
+++ b/src/yunohost/certificate.py
@@ -43,7 +43,8 @@ from yunohost.utils.network import get_public_ip
from moulinette import m18n
from yunohost.app import app_ssowatconf
-from yunohost.service import _run_service_command, service_regen_conf
+from yunohost.service import _run_service_command
+from yunohost.regenconf import regen_conf
from yunohost.log import OperationLogger
logger = getActionLogger('yunohost.certmanager')
@@ -806,7 +807,7 @@ def _enable_certificate(domain, new_cert_folder):
if os.path.isfile('/etc/yunohost/installed'):
# regen nginx conf to be sure it integrates OCSP Stapling
# (We don't do this yet if postinstall is not finished yet)
- service_regen_conf(names=['nginx'])
+ regen_conf(names=['nginx'])
_run_service_command("reload", "nginx")
@@ -924,7 +925,7 @@ def _regen_dnsmasq_if_needed():
break
if do_regen:
- service_regen_conf(["dnsmasq"])
+ regen_conf(["dnsmasq"])
def _name_self_CA():
diff --git a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
index 080cc0163..39a7d34e3 100644
--- a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
+++ b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
@@ -8,10 +8,10 @@ from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import mkdir, rm
from yunohost.tools import Migration
-from yunohost.service import service_regen_conf, \
- _get_conf_hashes, \
+from yunohost.service import _get_conf_hashes, \
_calculate_hash, \
_run_service_command
+from yunohost.regen_conf import regen_conf
from yunohost.settings import settings_set
from yunohost.utils.error import YunohostError
@@ -64,7 +64,7 @@ class MyMigration(Migration):
if os.path.exists('/etc/yunohost/from_script'):
rm('/etc/yunohost/from_script')
copyfile(SSHD_CONF, '/etc/ssh/sshd_config.bkp')
- service_regen_conf(names=['ssh'], force=True)
+ regen_conf(names=['ssh'], force=True)
copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF)
# Restart ssh and backward if it fail
diff --git a/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py b/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py
index 0976f1354..fce44298d 100644
--- a/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py
+++ b/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py
@@ -6,9 +6,9 @@ from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import chown
from yunohost.tools import Migration
-from yunohost.service import service_regen_conf, \
- _get_conf_hashes, \
+from yunohost.service import _get_conf_hashes, \
_calculate_hash
+from yunohost.regenconf import regen_conf
from yunohost.settings import settings_set, settings_get
from yunohost.utils.error import YunohostError
from yunohost.backup import ARCHIVES_PATH
@@ -36,7 +36,7 @@ class MyMigration(Migration):
def migrate(self):
settings_set("service.ssh.allow_deprecated_dsa_hostkey", False)
- service_regen_conf(names=['ssh'], force=True)
+ regen_conf(names=['ssh'], force=True)
# Update local archives folder permissions, so that
# admin can scp archives out of the server
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 3d46691f8..54ed81dfb 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -34,7 +34,7 @@ from moulinette.utils.log import getActionLogger
import yunohost.certificate
-from yunohost.service import service_regen_conf
+from yunohost.regenconf import regen_conf
from yunohost.utils.network import get_public_ip
from yunohost.log import is_unit_operation
@@ -111,7 +111,7 @@ def domain_add(operation_logger, auth, domain, dyndns=False):
# Don't regen these conf if we're still in postinstall
if os.path.exists('/etc/yunohost/installed'):
- service_regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd'])
+ regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd'])
app_ssowatconf(auth)
except Exception:
@@ -164,7 +164,7 @@ def domain_remove(operation_logger, auth, domain, force=False):
else:
raise YunohostError('domain_deletion_failed')
- service_regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix'])
+ regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix'])
app_ssowatconf(auth)
hook_callback('post_domain_remove', args=[domain])
diff --git a/src/yunohost/service.py b/src/yunohost/service.py
index ab0e791d8..d088f0029 100644
--- a/src/yunohost/service.py
+++ b/src/yunohost/service.py
@@ -410,6 +410,19 @@ def service_log(name, number=50):
return result
+def service_regen_conf(names=[], with_diff=False, force=False, dry_run=False,
+ list_pending=False):
+
+ services = _get_services()
+ for name in names:
+ if name not in services:
+ raise YunohostError('service_unknown', service=service)
+
+ logger.warning(m18n.n("service_regen_conf_is_deprecated"))
+
+ return regen_conf(names, with_diff, force, dry_run, list_pending)
+
+
def _run_service_command(action, service):
"""
Run services management command (start, stop, enable, disable, restart, reload)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index b2fbf380c..deec0746f 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -47,7 +47,8 @@ from yunohost.app import app_fetchlist, app_info, app_upgrade, app_ssowatconf, a
from yunohost.domain import domain_add, domain_list, _get_maindomain, _set_maindomain
from yunohost.dyndns import _dyndns_available, _dyndns_provides
from yunohost.firewall import firewall_upnp
-from yunohost.service import service_status, service_regen_conf, service_log, service_start, service_enable
+from yunohost.service import service_status, service_log, service_start, service_enable
+from yunohost.regenconf import regen_conf
from yunohost.monitor import monitor_disk, monitor_system
from yunohost.utils.packages import ynh_packages_version
from yunohost.utils.network import get_public_ip
@@ -207,7 +208,7 @@ def tools_maindomain(operation_logger, auth, new_domain=None):
# Regen configurations
try:
with open('/etc/yunohost/installed', 'r'):
- service_regen_conf()
+ regen_conf()
except IOError:
pass
@@ -325,7 +326,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
operation_logger.start()
logger.info(m18n.n('yunohost_installing'))
- service_regen_conf(['nslcd', 'nsswitch'], force=True)
+ regen_conf(['nslcd', 'nsswitch'], force=True)
# Initialize LDAP for YunoHost
# TODO: Improve this part by integrate ldapinit into conf_regen hook
@@ -376,7 +377,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
os.system('chmod 644 /etc/ssowat/conf.json.persistent')
# Create SSL CA
- service_regen_conf(['ssl'], force=True)
+ regen_conf(['ssl'], force=True)
ssl_dir = '/usr/share/yunohost/yunohost-config/ssl/yunoCA'
# (Update the serial so that it's specific to this very instance)
os.system("openssl rand -hex 19 > %s/serial" % ssl_dir)
@@ -405,7 +406,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
logger.success(m18n.n('yunohost_ca_creation_success'))
# New domain config
- service_regen_conf(['nsswitch'], force=True)
+ regen_conf(['nsswitch'], force=True)
domain_add(auth, domain, dyndns)
tools_maindomain(auth, domain)
@@ -433,7 +434,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
service_enable("yunohost-firewall")
service_start("yunohost-firewall")
- service_regen_conf(force=True)
+ regen_conf(force=True)
# Restore original ssh conf, as chosen by the
# admin during the initial install
@@ -450,13 +451,18 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
else:
# We need to explicitly ask the regen conf to regen ssh
# (by default, i.e. first argument = None, it won't because it's too touchy)
- service_regen_conf(names=["ssh"], force=True)
+ regen_conf(names=["ssh"], force=True)
logger.success(m18n.n('yunohost_configured'))
logger.warning(m18n.n('recommend_to_add_first_user'))
+def tools_regen_conf(names=[], with_diff=False, force=False, dry_run=False,
+ list_pending=False):
+ return regen_conf(names, with_diff, force, dry_run, list_pending)
+
+
def tools_update(ignore_apps=False, ignore_packages=False):
"""
Update apps & package cache, then display changelog
@@ -693,7 +699,7 @@ def tools_diagnosis(auth, private=False):
# Domains
diagnosis['private']['domains'] = domain_list(auth)['domains']
- diagnosis['private']['regen_conf'] = service_regen_conf(with_diff=True, dry_run=True)
+ diagnosis['private']['regen_conf'] = regen_conf(with_diff=True, dry_run=True)
try:
diagnosis['security'] = {
From 39891b228c393986101cdbf5093eaa9f1f2227c4 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 17:54:24 +0100
Subject: [PATCH 046/199] Inteface with regenconf.yml instead of services.yml
---
src/yunohost/regenconf.py | 39 +++++++++++++++------------------------
1 file changed, 15 insertions(+), 24 deletions(-)
diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py
index 4104e2491..783b50c4a 100644
--- a/src/yunohost/regenconf.py
+++ b/src/yunohost/regenconf.py
@@ -39,6 +39,7 @@ from yunohost.hook import hook_callback, hook_list
BASE_CONF_PATH = '/home/yunohost.conf'
BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup')
PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, 'pending')
+REGEN_CONF_FILE = '/etc/yunohost/regenconf.yml'
logger = log.getActionLogger('yunohost.regenconf')
@@ -290,39 +291,28 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
return result
-def _get_services():
+def _get_regenconf_infos():
"""
- Get a dict of managed services with their parameters
-
+ Get a dict of regen conf informations
"""
try:
- with open('/etc/yunohost/services.yml', 'r') as f:
- services = yaml.load(f)
+ with open(REGEN_CONF_FILE, 'r') as f:
+ return yaml.load(f)
except:
return {}
- else:
- # some services are marked as None to remove them from YunoHost
- # filter this
- for key, value in services.items():
- if value is None:
- del services[key]
-
- return services
-def _save_services(services):
+def _save_regenconf_infos(infos):
"""
- Save managed services to files
-
+ Save the regen conf informations
Keyword argument:
- services -- A dict of managed services with their parameters
-
+ categories -- A dict containing the regenconf infos
"""
try:
- with open('/etc/yunohost/services.yml', 'w') as f:
- yaml.safe_dump(services, f, default_flow_style=False)
+ with open(REGEN_CONF_FILE, 'w') as f:
+ yaml.safe_dump(infos, f, default_flow_style=False)
except Exception as e:
- logger.warning('Error while saving services, exception: %s', e, exc_info=1)
+ logger.warning('Error while saving regenconf infos, exception: %s', e, exc_info=1)
raise
@@ -426,7 +416,7 @@ def _get_pending_conf(categories=[]):
def _get_conf_hashes(category):
"""Get the registered conf hashes for a category"""
- categories = _get_categories()
+ categories = _get_regenconf_infos()
if category not in categories:
logger.debug("category %s is not in categories.yml yet.", category)
@@ -444,7 +434,8 @@ def _update_conf_hashes(category, hashes):
"""Update the registered conf hashes for a category"""
logger.debug("updating conf hashes for '%s' with: %s",
category, hashes)
- categories = _get_categories()
+
+ categories = _get_regenconf_infos()
category_conf = categories.get(category, {})
# Handle the case where categories[category] is set to null in the yaml
@@ -453,7 +444,7 @@ def _update_conf_hashes(category, hashes):
category_conf['conffiles'] = hashes
categories[category] = category_conf
- _save_categories(categories)
+ _save_regenconf_infos(categories)
def _process_regen_conf(system_conf, new_conf=None, save=True):
From 96bd6f8deb5683475bb5daa23ad2489419e909cc Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 18:50:46 +0100
Subject: [PATCH 047/199] Fix a few things for service_regen_conf backward
compatibility
---
src/yunohost/service.py | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/service.py b/src/yunohost/service.py
index d088f0029..56cac7a55 100644
--- a/src/yunohost/service.py
+++ b/src/yunohost/service.py
@@ -414,12 +414,20 @@ def service_regen_conf(names=[], with_diff=False, force=False, dry_run=False,
list_pending=False):
services = _get_services()
+
+ if isinstance(names, str):
+ names = [names]
+
for name in names:
- if name not in services:
- raise YunohostError('service_unknown', service=service)
+ if name not in services.keys():
+ raise YunohostError('service_unknown', service=name)
+
+ if names is []:
+ names = services.keys()
logger.warning(m18n.n("service_regen_conf_is_deprecated"))
+ from yunohost.regenconf import regen_conf
return regen_conf(names, with_diff, force, dry_run, list_pending)
From 0ebbb83191273ca716ecaf1c128ece0705b84c82 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 19:03:43 +0100
Subject: [PATCH 048/199] Add migration for services.yml on existing instance
---
data/templates/yunohost/services.yml | 9 ++--
.../0009_decouple_regenconf_from_services.py | 42 +++++++++++++++++++
src/yunohost/regenconf.py | 12 ++++++
3 files changed, 57 insertions(+), 6 deletions(-)
create mode 100644 src/yunohost/data_migrations/0009_decouple_regenconf_from_services.py
diff --git a/data/templates/yunohost/services.yml b/data/templates/yunohost/services.yml
index 62509e1e9..0d79b182f 100644
--- a/data/templates/yunohost/services.yml
+++ b/data/templates/yunohost/services.yml
@@ -20,8 +20,6 @@ mysql:
glances: {}
ssh:
log: /var/log/auth.log
-ssl:
- status: null
metronome:
log: [/var/log/metronome/metronome.log,/var/log/metronome/metronome.err]
slapd:
@@ -34,10 +32,9 @@ yunohost-firewall:
need_lock: true
nslcd:
log: /var/log/syslog
-nsswitch:
- status: null
-yunohost:
- status: null
+nsswitch: null
+ssl: null
+yunohost: null
bind9: null
tahoe-lafs: null
memcached: null
diff --git a/src/yunohost/data_migrations/0009_decouple_regenconf_from_services.py b/src/yunohost/data_migrations/0009_decouple_regenconf_from_services.py
new file mode 100644
index 000000000..e65aadfdf
--- /dev/null
+++ b/src/yunohost/data_migrations/0009_decouple_regenconf_from_services.py
@@ -0,0 +1,42 @@
+import os
+
+from moulinette import m18n
+from moulinette.utils.log import getActionLogger
+
+from moulinette.utils.filesystem import read_file
+from yunohost.service import _get_services, _save_services
+from yunohost.regenconf import _update_conf_hashes
+
+from yunohost.tools import Migration
+
+logger = getActionLogger('yunohost.migration')
+
+
+class MyMigration(Migration):
+ """
+ Decouple the regen conf mechanism from the concept of services
+ """
+
+ def migrate(self):
+
+ if "conffiles" not in read_file("/etc/yunohost/services.yml") \
+ or os.path.exists("/etc/yunohost/regenconf.yml"):
+ logger.warning(m18n.n("migration_0009_not_needed"))
+ return
+
+ # For all services
+ services = _get_services()
+ for service, infos in services.items():
+ # If there are some conffiles (file hashes)
+ if "conffiles" in infos.keys():
+ # Save them using the new regen conf thingy
+ _update_conf_hashes(service, infos["conffiles"])
+ # And delete the old conffile key from the service infos
+ del services[service]["conffiles"]
+
+ # (Actually save the modification of services)
+ _save_services(services)
+
+ def backward(self):
+
+ pass
diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py
index 783b50c4a..3ea8ccb6d 100644
--- a/src/yunohost/regenconf.py
+++ b/src/yunohost/regenconf.py
@@ -31,6 +31,7 @@ from datetime import datetime
from moulinette import m18n
from moulinette.utils import log, filesystem
+from moulinette.utils.filesystem import read_file
from yunohost.utils.error import YunohostError
from yunohost.log import is_unit_operation
@@ -60,6 +61,17 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
list_pending -- List pending configuration files and exit
"""
+
+ # Legacy code to automatically run the migration
+ # This is required because regen_conf is called before the migration call
+ # in debian's postinst script
+ if os.path.exists("/etc/yunohost/installed") \
+ and ("conffiles" in read_file("/etc/yunohost/services.yml") \
+ or not os.path.exists("/etc/yunohost/regenconf.yml")):
+ from yunohost.tools import _get_migration_by_name
+ migration = _get_migration_by_name("decouple_regenconf_from_services")
+ migration.migrate()
+
result = {}
# Return the list of pending conf
From d7d224286237f7bb8733bdccb19ad348674f1331 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 19:10:01 +0100
Subject: [PATCH 049/199] Fix imports in some migrations
---
src/yunohost/data_migrations/0003_migrate_to_stretch.py | 6 +++---
.../0007_ssh_conf_managed_by_yunohost_step1.py | 7 ++-----
.../0008_ssh_conf_managed_by_yunohost_step2.py | 3 +--
3 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/src/yunohost/data_migrations/0003_migrate_to_stretch.py b/src/yunohost/data_migrations/0003_migrate_to_stretch.py
index 438393216..0db719e15 100644
--- a/src/yunohost/data_migrations/0003_migrate_to_stretch.py
+++ b/src/yunohost/data_migrations/0003_migrate_to_stretch.py
@@ -10,9 +10,9 @@ from moulinette.utils.filesystem import read_file
from yunohost.tools import Migration
from yunohost.app import unstable_apps
-from yunohost.service import (_run_service_command,
- manually_modified_files,
- manually_modified_files_compared_to_debian_default)
+from yunohost.service import _run_service_command
+from yunohost.regenconf import (manually_modified_files,
+ manually_modified_files_compared_to_debian_default)
from yunohost.utils.filesystem import free_space_in_directory
from yunohost.utils.packages import get_installed_version
from yunohost.utils.network import get_network_interfaces
diff --git a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
index 39a7d34e3..959b17fb5 100644
--- a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
+++ b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
@@ -3,15 +3,12 @@ import re
from shutil import copyfile
-from moulinette import m18n
from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import mkdir, rm
from yunohost.tools import Migration
-from yunohost.service import _get_conf_hashes, \
- _calculate_hash, \
- _run_service_command
-from yunohost.regen_conf import regen_conf
+from yunohost.service import _run_service_command
+from yunohost.regenconf import regen_conf
from yunohost.settings import settings_set
from yunohost.utils.error import YunohostError
diff --git a/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py b/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py
index fce44298d..8984440bd 100644
--- a/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py
+++ b/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py
@@ -6,8 +6,7 @@ from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import chown
from yunohost.tools import Migration
-from yunohost.service import _get_conf_hashes, \
- _calculate_hash
+from yunohost.regenconf import _get_conf_hashes, _calculate_hash
from yunohost.regenconf import regen_conf
from yunohost.settings import settings_set, settings_get
from yunohost.utils.error import YunohostError
From 984646bb3cd6866ce36e146620ad62fe3361e048 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 19:22:19 +0100
Subject: [PATCH 050/199] Implement strings for migration
---
locales/en.json | 2 ++
1 file changed, 2 insertions(+)
diff --git a/locales/en.json b/locales/en.json
index 5ab2a749b..a606a13dc 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -286,6 +286,7 @@
"migration_description_0006_sync_admin_and_root_passwords": "Synchronize admin and root passwords",
"migration_description_0007_ssh_conf_managed_by_yunohost_step1": "Let the SSH configuration be managed by YunoHost (step 1, automatic)",
"migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Let the SSH configuration be managed by YunoHost (step 2, manual)",
+ "migration_description_0009_decouple_regenconf_from_services": "Decouple the regen-conf mechanism from services",
"migration_0003_backward_impossible": "The stretch migration cannot be reverted.",
"migration_0003_start": "Starting migration to Stretch. The logs will be available in {logfile}.",
"migration_0003_patching_sources_list": "Patching the sources.lists…",
@@ -311,6 +312,7 @@
"migration_0008_dsa": " - the DSA key will be disabled. Hence, you might need to invalidate a spooky warning from your SSH client, and recheck the fingerprint of your server;",
"migration_0008_warning": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.",
"migration_0008_no_warning": "No major risk has been indentified about overriding your SSH configuration - but we can't be absolutely sure ;)! If you agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.",
+ "migration_0009_not_needed": "This migration already happened somehow ? Skipping.",
"migrations_backward": "Migrating backward.",
"migrations_bad_value_for_target": "Invalid number for target argument, available migrations numbers are 0 or {}",
"migrations_cant_reach_migration_file": "Can't access migrations files at path %s",
From 69b8f7294b91360f3e937a2b3ab5cf7bd9515331 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 19:36:06 +0100
Subject: [PATCH 051/199] Fix log handling
---
locales/en.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/locales/en.json b/locales/en.json
index a606a13dc..c10e8c393 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -249,7 +249,7 @@
"log_selfsigned_cert_install": "Install self signed certificate on '{}' domain",
"log_letsencrypt_cert_renew": "Renew '{}' Let's encrypt certificate",
"log_service_enable": "Enable '{}' service",
- "log_service_regen_conf": "Regenerate system configurations '{}'",
+ "log_regen_conf": "Regenerate system configurations '{}'",
"log_user_create": "Add '{}' user",
"log_user_delete": "Delete '{}' user",
"log_user_update": "Update information of '{}' user",
From 1b7d25de96d215101547d08babfa2d884343518d Mon Sep 17 00:00:00 2001
From: Kayou
Date: Tue, 19 Feb 2019 00:03:46 +0100
Subject: [PATCH 052/199] Update psql
---
data/helpers.d/psql | 2 ++
1 file changed, 2 insertions(+)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index 2ef13482a..2feb6b0ac 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -1,3 +1,5 @@
+#!/bin/bash
+
# Create a master password and set up global settings
# Please always call this script in install and restore scripts
#
From b5ae91b34e8edd4cefe99ef56be891b72b663e48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pierre=20Bourr=C3=A9?=
Date: Tue, 19 Feb 2019 01:39:00 +0100
Subject: [PATCH 053/199] [WIP] Update
---
data/helpers.d/psql | 216 +++++++++++++++++++++++++++++++++-----------
1 file changed, 162 insertions(+), 54 deletions(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index 2feb6b0ac..20edb2fc5 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -1,75 +1,147 @@
#!/bin/bash
-# Create a master password and set up global settings
-# Please always call this script in install and restore scripts
-#
-# usage: ynh_psql_test_if_first_run
-ynh_psql_test_if_first_run() {
- if [ -f /etc/yunohost/psql ];
- then
- echo "PostgreSQL is already installed, no need to create master password"
- else
- local pgsql="$(ynh_string_random)"
- echo "$pgsql" > /etc/yunohost/psql
-
- if [ -e /etc/postgresql/9.4/ ]
- then
- local pg_hba=/etc/postgresql/9.4/main/pg_hba.conf
- elif [ -e /etc/postgresql/9.6/ ]
- then
- local pg_hba=/etc/postgresql/9.6/main/pg_hba.conf
- else
- ynh_die "postgresql shoud be 9.4 or 9.6"
- fi
-
- systemctl start postgresql
- sudo --login --user=postgres psql -c"ALTER user postgres WITH PASSWORD '$pgsql'" postgres
-
- # force all user to connect to local database using passwords
- # https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html#EXAMPLE-PG-HBA.CONF
- # Note: we can't use peer since YunoHost create users with nologin
- # See: https://github.com/YunoHost/yunohost/blob/unstable/data/helpers.d/user
- sed -i '/local\s*all\s*all\s*peer/i \
- local all all password' "$pg_hba"
- systemctl enable postgresql
- systemctl reload postgresql
- fi
-}
+PSQL_ROOT_PWD_FILE=/etc/yunohost/psql
# Open a connection as a user
#
# example: ynh_psql_connect_as 'user' 'pass' <<< "UPDATE ...;"
# example: ynh_psql_connect_as 'user' 'pass' < /path/to/file.sql
#
-# usage: ynh_psql_connect_as user pwd [db]
-# | arg: user - the user name to connect as
-# | arg: pwd - the user password
-# | arg: db - the database to connect to
+# usage: ynh_psql_connect_as --user=user --password=password [--database=database]
+# | arg: -u, --user - the user name to connect as
+# | arg: -p, --password - the user password
+# | arg: -d, --database - the database to connect to
ynh_psql_connect_as() {
- local user="$1"
- local pwd="$2"
- local db="$3"
- sudo --login --user=postgres PGUSER="$user" PGPASSWORD="$pwd" psql "$db"
+ # Declare an array to define the options of this helper.
+ local legacy_args=upd
+ declare -Ar args_array=( [u]=user= [p]=password= [d]=database= )
+ local user
+ local password
+ local database
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+ database="${database:-}"
+
+ sudo --login --user=postgres PGUSER="$user" PGPASSWORD="$password" psql "$database"
}
-# # Execute a command as root user
+# Execute a command as root user
#
-# usage: ynh_psql_execute_as_root sql [db]
-# | arg: sql - the SQL command to execute
+# usage: ynh_psql_execute_as_root --sql=sql [--database=database]
+# | arg: -s, --sql - the SQL command to execute
+# | arg: -d, --database - the database to connect to
ynh_psql_execute_as_root () {
- local sql="$1"
- sudo --login --user=postgres psql <<< "$sql"
+ # Declare an array to define the options of this helper.
+ local legacy_args=sd
+ declare -Ar args_array=( [s]=sql= [d]=database= )
+ local sql
+ local database
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+ database="${database:-}"
+
+ ynh_psql_connect_as --user="postgres" --password="$(sudo cat $PSQL_ROOT_PWD_FILE)" \
+ --database="$database" <<< "$sql"
}
# Execute a command from a file as root user
#
-# usage: ynh_psql_execute_file_as_root file [db]
-# | arg: file - the file containing SQL commands
-# | arg: db - the database to connect to
+# usage: ynh_psql_execute_file_as_root --file=file [--database=database]
+# | arg: -f, --file - the file containing SQL commands
+# | arg: -d, --database - the database to connect to
ynh_psql_execute_file_as_root() {
- local file="$1"
- local db="$2"
- sudo --login --user=postgres psql "$db" < "$file"
+ # Declare an array to define the options of this helper.
+ local legacy_args=fd
+ declare -Ar args_array=( [f]=file= [d]=database= )
+ local file
+ local database
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+ database="${database:-}"
+
+ ynh_psql_connect_as --user="postgres" --password="$(sudo cat $PSQL_ROOT_PWD_FILE)" \
+ --database="$database" < "$file"
+}
+
+# Create a database and grant optionnaly privilegies to a user
+#
+# [internal]
+#
+# usage: ynh_psql_create_db db [user [pwd]]
+# | arg: db - the database name to create
+# | arg: user - the user to grant privilegies
+# | arg: pwd - the password to identify user by
+ynh_psql_create_db() {
+ local db=$1
+
+ ynh_psql_create_user "$user" "$pwd"
+ sudo --login --user=postgres createdb --owner="$user" "$db"
+}
+
+# Drop a database
+#
+# [internal]
+#
+# If you intend to drop the database *and* the associated user,
+# consider using ynh_psql_remove_db instead.
+#
+# usage: ynh_psql_drop_db db
+# | arg: db - the database name to drop
+ynh_psql_drop_db() {
+ local db=$1
+ sudo --login --user=postgres dropdb $db
+}
+
+# Dump a database
+#
+# example: ynh_psql_dump_db 'roundcube' > ./dump.sql
+#
+# usage: ynh_psql_dump_db --database=database
+# | arg: -d, --database - the database name to dump
+# | ret: the psqldump output
+ynh_psql_dump_db() {
+ # Declare an array to define the options of this helper.
+ local legacy_args=d
+ declare -Ar args_array=( [d]=database= )
+ local database
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+
+ sudo --login --user=postgres pg_dump "$database"
+}
+
+# Create a user
+#
+# [internal]
+#
+# usage: ynh_psql_create_user user pwd [host]
+# | arg: user - the user name to create
+# | arg: pwd - the password to identify user by
+ynh_psql_create_user() {
+ local user=$1
+ local psql=$2
+ ynh_psql_execute_as_root "CREATE USER $user WITH PASSWORD '$pwd'"
+}
+
+# Check if a psql user exists
+#
+# usage: ynh_psql_user_exists --user=user
+# | arg: -u, --user - the user for which to check existence
+ynh_psql_user_exists()
+{
+ # Declare an array to define the options of this helper.
+ local legacy_args=u
+ declare -Ar args_array=( [u]=user= )
+ local user
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+
+ if [[ -z $(ynh_psql_execute_as_root --sql="SELECT 1 FROM pg_roles WHERE rolename='$user';") ]]
+ then
+ return 1
+ else
+ return 0
+ fi
}
# Create a database, an user and its password. Then store the password in the app's config
@@ -148,3 +220,39 @@ ynh_psql_drop_user() {
local user="$1"
sudo --login --user=postgres dropuser "$user"
}
+
+# Create a master password and set up global settings
+# Please always call this script in install and restore scripts
+#
+# usage: ynh_psql_test_if_first_run
+ynh_psql_test_if_first_run() {
+ if [ -f /etc/yunohost/psql ];
+ then
+ echo "PostgreSQL is already installed, no need to create master password"
+ else
+ local pgsql="$(ynh_string_random)"
+ echo "$pgsql" > /etc/yunohost/psql
+
+ if [ -e /etc/postgresql/9.4/ ]
+ then
+ local pg_hba=/etc/postgresql/9.4/main/pg_hba.conf
+ elif [ -e /etc/postgresql/9.6/ ]
+ then
+ local pg_hba=/etc/postgresql/9.6/main/pg_hba.conf
+ else
+ ynh_die "postgresql shoud be 9.4 or 9.6"
+ fi
+
+ systemctl start postgresql
+ sudo --login --user=postgres psql -c"ALTER user postgres WITH PASSWORD '$pgsql'" postgres
+
+ # force all user to connect to local database using passwords
+ # https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html#EXAMPLE-PG-HBA.CONF
+ # Note: we can't use peer since YunoHost create users with nologin
+ # See: https://github.com/YunoHost/yunohost/blob/unstable/data/helpers.d/user
+ sed -i '/local\s*all\s*all\s*peer/i \
+ local all all password' "$pg_hba"
+ systemctl enable postgresql
+ systemctl reload postgresql
+ fi
+}
\ No newline at end of file
From d5ca4dd88b3fe49d3c8b9a0780b97e61c1c0e89e Mon Sep 17 00:00:00 2001
From: Kayou
Date: Wed, 20 Feb 2019 00:21:44 +0100
Subject: [PATCH 054/199] Fix ynh_psql_user_exists
---
data/helpers.d/psql | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index 20edb2fc5..b6ba5afaf 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -120,7 +120,7 @@ ynh_psql_dump_db() {
ynh_psql_create_user() {
local user=$1
local psql=$2
- ynh_psql_execute_as_root "CREATE USER $user WITH PASSWORD '$pwd'"
+ ynh_psql_execute_as_root --sql="CREATE USER $user WITH PASSWORD '$pwd'"
}
# Check if a psql user exists
@@ -136,7 +136,7 @@ ynh_psql_user_exists()
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
- if [[ -z $(ynh_psql_execute_as_root --sql="SELECT 1 FROM pg_roles WHERE rolename='$user';") ]]
+ if [[ -n $(sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';") ]]
then
return 1
else
From d030628a9b36d869e39921f502b9e7f5b58bb1ad Mon Sep 17 00:00:00 2001
From: Kayou
Date: Wed, 20 Feb 2019 01:27:27 +0100
Subject: [PATCH 055/199] Update psql helper
---
data/helpers.d/psql | 264 +++++++++++++++++++++++---------------------
1 file changed, 137 insertions(+), 127 deletions(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index b6ba5afaf..fb9ffe013 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -12,15 +12,15 @@ PSQL_ROOT_PWD_FILE=/etc/yunohost/psql
# | arg: -p, --password - the user password
# | arg: -d, --database - the database to connect to
ynh_psql_connect_as() {
- # Declare an array to define the options of this helper.
- local legacy_args=upd
- declare -Ar args_array=( [u]=user= [p]=password= [d]=database= )
- local user
- local password
- local database
- # Manage arguments with getopts
- ynh_handle_getopts_args "$@"
- database="${database:-}"
+ # Declare an array to define the options of this helper.
+ local legacy_args=upd
+ declare -Ar args_array=([u]=user= [p]=password= [d]=database=)
+ local user
+ local password
+ local database
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+ database="${database:-}"
sudo --login --user=postgres PGUSER="$user" PGPASSWORD="$password" psql "$database"
}
@@ -30,18 +30,18 @@ ynh_psql_connect_as() {
# usage: ynh_psql_execute_as_root --sql=sql [--database=database]
# | arg: -s, --sql - the SQL command to execute
# | arg: -d, --database - the database to connect to
-ynh_psql_execute_as_root () {
- # Declare an array to define the options of this helper.
- local legacy_args=sd
- declare -Ar args_array=( [s]=sql= [d]=database= )
- local sql
- local database
- # Manage arguments with getopts
- ynh_handle_getopts_args "$@"
- database="${database:-}"
+ynh_psql_execute_as_root() {
+ # Declare an array to define the options of this helper.
+ local legacy_args=sd
+ declare -Ar args_array=([s]=sql= [d]=database=)
+ local sql
+ local database
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+ database="${database:-}"
- ynh_psql_connect_as --user="postgres" --password="$(sudo cat $PSQL_ROOT_PWD_FILE)" \
- --database="$database" <<< "$sql"
+ ynh_psql_connect_as --user="postgres" --password="$(sudo cat $PSQL_ROOT_PWD_FILE)" \
+ --database="$database" <<<"$sql"
}
# Execute a command from a file as root user
@@ -50,17 +50,17 @@ ynh_psql_execute_as_root () {
# | arg: -f, --file - the file containing SQL commands
# | arg: -d, --database - the database to connect to
ynh_psql_execute_file_as_root() {
- # Declare an array to define the options of this helper.
- local legacy_args=fd
- declare -Ar args_array=( [f]=file= [d]=database= )
- local file
- local database
- # Manage arguments with getopts
- ynh_handle_getopts_args "$@"
- database="${database:-}"
+ # Declare an array to define the options of this helper.
+ local legacy_args=fd
+ declare -Ar args_array=([f]=file= [d]=database=)
+ local file
+ local database
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+ database="${database:-}"
- ynh_psql_connect_as --user="postgres" --password="$(sudo cat $PSQL_ROOT_PWD_FILE)" \
- --database="$database" < "$file"
+ ynh_psql_connect_as --user="postgres" --password="$(sudo cat $PSQL_ROOT_PWD_FILE)" \
+ --database="$database" <"$file"
}
# Create a database and grant optionnaly privilegies to a user
@@ -72,10 +72,18 @@ ynh_psql_execute_file_as_root() {
# | arg: user - the user to grant privilegies
# | arg: pwd - the password to identify user by
ynh_psql_create_db() {
- local db=$1
+ local db=$1
- ynh_psql_create_user "$user" "$pwd"
- sudo --login --user=postgres createdb --owner="$user" "$db"
+ local sql="CREATE DATABASE ${db};"
+
+ # grant all privilegies to user
+ if [[ $# -gt 1 ]]; then
+ #ynh_psql_create_user "$user" "$pwd"
+ sql+=" GRANT ALL PRIVILEGES ON ${db} TO ${2} WITH GRANT OPTION;"
+ fi
+
+ #sudo --login --user=postgres createdb --owner="$user" "$db"
+ ynh_psql_execute_as_root --sql="$sql"
}
# Drop a database
@@ -89,7 +97,7 @@ ynh_psql_create_db() {
# | arg: db - the database name to drop
ynh_psql_drop_db() {
local db=$1
- sudo --login --user=postgres dropdb $db
+ sudo --login --user=postgres dropdb $db
}
# Dump a database
@@ -100,14 +108,14 @@ ynh_psql_drop_db() {
# | arg: -d, --database - the database name to dump
# | ret: the psqldump output
ynh_psql_dump_db() {
- # Declare an array to define the options of this helper.
- local legacy_args=d
- declare -Ar args_array=( [d]=database= )
- local database
- # Manage arguments with getopts
- ynh_handle_getopts_args "$@"
+ # Declare an array to define the options of this helper.
+ local legacy_args=d
+ declare -Ar args_array=([d]=database=)
+ local database
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
- sudo --login --user=postgres pg_dump "$database"
+ sudo --login --user=postgres pg_dump "$database"
}
# Create a user
@@ -127,21 +135,48 @@ ynh_psql_create_user() {
#
# usage: ynh_psql_user_exists --user=user
# | arg: -u, --user - the user for which to check existence
-ynh_psql_user_exists()
-{
- # Declare an array to define the options of this helper.
- local legacy_args=u
- declare -Ar args_array=( [u]=user= )
- local user
- # Manage arguments with getopts
- ynh_handle_getopts_args "$@"
+ynh_psql_user_exists() {
+ # Declare an array to define the options of this helper.
+ local legacy_args=u
+ declare -Ar args_array=([u]=user=)
+ local user
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
- if [[ -n $(sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';") ]]
- then
- return 1
- else
- return 0
- fi
+ if [[ -n $(sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';") ]]; then
+ return 1
+ else
+ return 0
+ fi
+}
+
+# Check if a psql database exists
+#
+# usage: ynh_psql_database_exists --database=database
+# | arg: -d, --database - the database for which to check existence
+ynh_psql_database_exists() {
+ # Declare an array to define the options of this helper.
+ local legacy_args=u
+ declare -Ar args_array=([u]=database=)
+ local database
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+
+ if [[ -n $(sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';") ]]; then
+ return 1
+ else
+ return 0
+ fi
+}
+
+# Drop a user
+#
+# [internal]
+#
+# usage: ynh_psql_drop_user user
+# | arg: user - the user name to drop
+ynh_psql_drop_user() {
+ ynh_psql_execute_as_root --sql="DROP USER '${1}';"
}
# Create a database, an user and its password. Then store the password in the app's config
@@ -149,76 +184,54 @@ ynh_psql_user_exists()
# After executing this helper, the password of the created database will be available in $db_pwd
# It will also be stored as "psqlpwd" into the app settings.
#
-# usage: ynh_psql_setup_db user name [pwd]
-# | arg: user - Owner of the database
-# | arg: name - Name of the database
-# | arg: pwd - Password of the database. If not given, a password will be generated
-ynh_psql_setup_db () {
- local db_user="$1"
- local db_name="$2"
- local new_db_pwd=$(ynh_string_random) # Generate a random password
- # If $3 is not given, use new_db_pwd instead for db_pwd.
- local db_pwd="${3:-$new_db_pwd}"
- ynh_psql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database
- ynh_app_setting_set "$app" psqlpwd "$db_pwd" # Store the password in the app's config
+# usage: ynh_psql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
+# | arg: -u, --db_user - Owner of the database
+# | arg: -n, --db_name - Name of the database
+# | arg: -p, --db_pwd - Password of the database. If not given, a password will be generated
+ynh_psql_setup_db() {
+ # Declare an array to define the options of this helper.
+ local legacy_args=unp
+ declare -Ar args_array=([u]=db_user= [n]=db_name= [p]=db_pwd=)
+ local db_user
+ local db_name
+ db_pwd=""
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+
+ local new_db_pwd=$(ynh_string_random) # Generate a random password
+ # If $db_pwd is not given, use new_db_pwd instead for db_pwd
+ db_pwd="${db_pwd:-$new_db_pwd}"
+
+ ynh_psql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database
+ ynh_app_setting_set --app=$app --key=psqlpwd --value=$db_pwd # Store the password in the app's config
}
-# Create a database and grant privilegies to a user
+# Remove a database if it exists, and the associated user
#
-# usage: ynh_psql_create_db db [user [pwd]]
-# | arg: db - the database name to create
-# | arg: user - the user to grant privilegies
-# | arg: pwd - the user password
-ynh_psql_create_db() {
- local db="$1"
- local user="$2"
- local pwd="$3"
- ynh_psql_create_user "$user" "$pwd"
- sudo --login --user=postgres createdb --owner="$user" "$db"
-}
-
-# Drop a database
-#
-# usage: ynh_psql_drop_db db
-# | arg: db - the database name to drop
-# | arg: user - the user to drop
+# usage: ynh_psql_remove_db --db_user=user --db_name=name
+# | arg: -u, --db_user - Owner of the database
+# | arg: -n, --db_name - Name of the database
ynh_psql_remove_db() {
- local db="$1"
- local user="$2"
- sudo --login --user=postgres dropdb "$db"
- ynh_psql_drop_user "$user"
-}
+ # Declare an array to define the options of this helper.
+ local legacy_args=un
+ declare -Ar args_array=([u]=db_user= [n]=db_name=)
+ local db_user
+ local db_name
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
-# Dump a database
-#
-# example: ynh_psql_dump_db 'roundcube' > ./dump.sql
-#
-# usage: ynh_psql_dump_db db
-# | arg: db - the database name to dump
-# | ret: the psqldump output
-ynh_psql_dump_db() {
- local db="$1"
- sudo --login --user=postgres pg_dump "$db"
-}
+ local psql_root_password=$(sudo cat $PSQL_ROOT_PWD_FILE)
+ if ynh_psql_database_exists "$db_name"; then # Check if the database exists
+ echo "Removing database $db_name" >&2
+ ynh_psql_drop_db $db_name # Remove the database
+ else
+ echo "Database $db_name not found" >&2
+ fi
-
-# Create a user
-#
-# usage: ynh_psql_create_user user pwd [host]
-# | arg: user - the user name to create
-ynh_psql_create_user() {
- local user="$1"
- local pwd="$2"
- sudo --login --user=postgres psql -c"CREATE USER $user WITH PASSWORD '$pwd'" postgres
-}
-
-# Drop a user
-#
-# usage: ynh_psql_drop_user user
-# | arg: user - the user name to drop
-ynh_psql_drop_user() {
- local user="$1"
- sudo --login --user=postgres dropuser "$user"
+ # Remove psql user if it exists
+ if $(ynh_psql_user_exists --user=$db_user); then
+ ynh_psql_drop_user $db_user
+ fi
}
# Create a master password and set up global settings
@@ -226,18 +239,15 @@ ynh_psql_drop_user() {
#
# usage: ynh_psql_test_if_first_run
ynh_psql_test_if_first_run() {
- if [ -f /etc/yunohost/psql ];
- then
+ if [ -f /etc/yunohost/psql ]; then
echo "PostgreSQL is already installed, no need to create master password"
else
local pgsql="$(ynh_string_random)"
- echo "$pgsql" > /etc/yunohost/psql
+ echo "$pgsql" >/etc/yunohost/psql
- if [ -e /etc/postgresql/9.4/ ]
- then
+ if [ -e /etc/postgresql/9.4/ ]; then
local pg_hba=/etc/postgresql/9.4/main/pg_hba.conf
- elif [ -e /etc/postgresql/9.6/ ]
- then
+ elif [ -e /etc/postgresql/9.6/ ]; then
local pg_hba=/etc/postgresql/9.6/main/pg_hba.conf
else
ynh_die "postgresql shoud be 9.4 or 9.6"
@@ -255,4 +265,4 @@ ynh_psql_test_if_first_run() {
systemctl enable postgresql
systemctl reload postgresql
fi
-}
\ No newline at end of file
+}
From f2a4be29920261f0f95921be1cbf84ac2c516374 Mon Sep 17 00:00:00 2001
From: Kayou
Date: Wed, 20 Feb 2019 01:39:22 +0100
Subject: [PATCH 056/199] fix ynh_psql_create_db
---
data/helpers.d/psql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index fb9ffe013..7843212eb 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -79,7 +79,7 @@ ynh_psql_create_db() {
# grant all privilegies to user
if [[ $# -gt 1 ]]; then
#ynh_psql_create_user "$user" "$pwd"
- sql+=" GRANT ALL PRIVILEGES ON ${db} TO ${2} WITH GRANT OPTION;"
+ sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${2} WITH GRANT OPTION;"
fi
#sudo --login --user=postgres createdb --owner="$user" "$db"
From a7af86832eaa134f6613ebff47244841dec8361a Mon Sep 17 00:00:00 2001
From: Kayou
Date: Wed, 20 Feb 2019 01:56:14 +0100
Subject: [PATCH 057/199] Small fix
---
data/helpers.d/psql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index 7843212eb..d4888982c 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -221,7 +221,7 @@ ynh_psql_remove_db() {
ynh_handle_getopts_args "$@"
local psql_root_password=$(sudo cat $PSQL_ROOT_PWD_FILE)
- if ynh_psql_database_exists "$db_name"; then # Check if the database exists
+ if $(ynh_psql_database_exists "$db_name"); then # Check if the database exists
echo "Removing database $db_name" >&2
ynh_psql_drop_db $db_name # Remove the database
else
From 203b8c06a999766ecf2229588787c203ca37c582 Mon Sep 17 00:00:00 2001
From: Kayou
Date: Wed, 20 Feb 2019 02:18:24 +0100
Subject: [PATCH 058/199] Fix ynh_psql_user_exists and ynh_psql_database_exists
---
data/helpers.d/psql | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index d4888982c..a3069ce11 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -143,7 +143,7 @@ ynh_psql_user_exists() {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
- if [[ -n $(sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';") ]]; then
+ if [[ -z $(sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';") ]]; then
return 1
else
return 0
@@ -162,7 +162,7 @@ ynh_psql_database_exists() {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
- if [[ -n $(sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';") ]]; then
+ if [[ -z $(sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';") ]]; then
return 1
else
return 0
From a20b0e96c809a4b7d23597eea82bbc7f6ce0baa5 Mon Sep 17 00:00:00 2001
From: Kayou
Date: Wed, 20 Feb 2019 02:18:38 +0100
Subject: [PATCH 059/199] Fix ynh_psql_setup_db
---
data/helpers.d/psql | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index a3069ce11..a48aef0fb 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -78,11 +78,9 @@ ynh_psql_create_db() {
# grant all privilegies to user
if [[ $# -gt 1 ]]; then
- #ynh_psql_create_user "$user" "$pwd"
sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${2} WITH GRANT OPTION;"
fi
- #sudo --login --user=postgres createdb --owner="$user" "$db"
ynh_psql_execute_as_root --sql="$sql"
}
@@ -128,7 +126,7 @@ ynh_psql_dump_db() {
ynh_psql_create_user() {
local user=$1
local psql=$2
- ynh_psql_execute_as_root --sql="CREATE USER $user WITH PASSWORD '$pwd'"
+ ynh_psql_execute_as_root --sql="CREATE USER $user WITH PASSWORD $pwd"
}
# Check if a psql user exists
@@ -176,7 +174,7 @@ ynh_psql_database_exists() {
# usage: ynh_psql_drop_user user
# | arg: user - the user name to drop
ynh_psql_drop_user() {
- ynh_psql_execute_as_root --sql="DROP USER '${1}';"
+ ynh_psql_execute_as_root --sql="DROP USER ${1};"
}
# Create a database, an user and its password. Then store the password in the app's config
@@ -202,6 +200,10 @@ ynh_psql_setup_db() {
# If $db_pwd is not given, use new_db_pwd instead for db_pwd
db_pwd="${db_pwd:-$new_db_pwd}"
+ if [ $(ynh_psql_user_exists --user=$db_user) ]; then
+ ynh_psql_create_user "$db_name" "$db_user" "$db_pwd"
+ fi
+
ynh_psql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database
ynh_app_setting_set --app=$app --key=psqlpwd --value=$db_pwd # Store the password in the app's config
}
@@ -230,7 +232,10 @@ ynh_psql_remove_db() {
# Remove psql user if it exists
if $(ynh_psql_user_exists --user=$db_user); then
+ echo "Removing user $db_user" >&2
ynh_psql_drop_user $db_user
+ else
+ echo "User $db_user not found" >&2
fi
}
From f0d8f88121361d2677bb5c2a403c8a2f094d0ed4 Mon Sep 17 00:00:00 2001
From: Kayou
Date: Wed, 20 Feb 2019 23:57:12 +0100
Subject: [PATCH 060/199] Change $psql to $pwd
---
data/helpers.d/psql | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index a48aef0fb..0c7d70caf 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -125,8 +125,8 @@ ynh_psql_dump_db() {
# | arg: pwd - the password to identify user by
ynh_psql_create_user() {
local user=$1
- local psql=$2
- ynh_psql_execute_as_root --sql="CREATE USER $user WITH PASSWORD $pwd"
+ local pwd=$2
+ ynh_psql_execute_as_root --sql="CREATE USER $user WITH ENCRYPTED PASSWORD '$pwd'"
}
# Check if a psql user exists
From 3ae5955590e0e9ade4cf3c3625e1cb54e574b66c Mon Sep 17 00:00:00 2001
From: Kayou
Date: Wed, 20 Feb 2019 23:58:26 +0100
Subject: [PATCH 061/199] Remove some $() and []
---
data/helpers.d/psql | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index 0c7d70caf..f960e6297 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -200,8 +200,8 @@ ynh_psql_setup_db() {
# If $db_pwd is not given, use new_db_pwd instead for db_pwd
db_pwd="${db_pwd:-$new_db_pwd}"
- if [ $(ynh_psql_user_exists --user=$db_user) ]; then
- ynh_psql_create_user "$db_name" "$db_user" "$db_pwd"
+ if ! ynh_psql_user_exists --user=$db_user; then
+ ynh_psql_create_user "$db_user" "$db_pwd"
fi
ynh_psql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database
@@ -223,7 +223,7 @@ ynh_psql_remove_db() {
ynh_handle_getopts_args "$@"
local psql_root_password=$(sudo cat $PSQL_ROOT_PWD_FILE)
- if $(ynh_psql_database_exists "$db_name"); then # Check if the database exists
+ if ynh_psql_database_exists --database=$db_name; then # Check if the database exists
echo "Removing database $db_name" >&2
ynh_psql_drop_db $db_name # Remove the database
else
@@ -231,7 +231,7 @@ ynh_psql_remove_db() {
fi
# Remove psql user if it exists
- if $(ynh_psql_user_exists --user=$db_user); then
+ if ynh_psql_user_exists --user=$db_user; then
echo "Removing user $db_user" >&2
ynh_psql_drop_user $db_user
else
From 9b8bd79a37655585e806d04ef96534c96caaf19b Mon Sep 17 00:00:00 2001
From: Kayou
Date: Thu, 21 Feb 2019 00:16:57 +0100
Subject: [PATCH 062/199] Don't use [[]] anymore
---
data/helpers.d/psql | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index f960e6297..bdc9a07c2 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -141,7 +141,7 @@ ynh_psql_user_exists() {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
- if [[ -z $(sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';") ]]; then
+ if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';" | grep --quiet "$user" ; then
return 1
else
return 0
@@ -160,7 +160,7 @@ ynh_psql_database_exists() {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
- if [[ -z $(sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';") ]]; then
+ if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$user"; then
return 1
else
return 0
From 81bc9987bdb8b75414fabf8dfd54ce6f59e68ab1 Mon Sep 17 00:00:00 2001
From: Kayou
Date: Thu, 21 Feb 2019 01:03:10 +0100
Subject: [PATCH 063/199] rework ynh_psql_create_db
---
data/helpers.d/psql | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index bdc9a07c2..e427582d6 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -67,18 +67,18 @@ ynh_psql_execute_file_as_root() {
#
# [internal]
#
-# usage: ynh_psql_create_db db [user [pwd]]
+# usage: ynh_psql_create_db db [user]
# | arg: db - the database name to create
# | arg: user - the user to grant privilegies
-# | arg: pwd - the password to identify user by
ynh_psql_create_db() {
local db=$1
+ local user=$2
local sql="CREATE DATABASE ${db};"
# grant all privilegies to user
- if [[ $# -gt 1 ]]; then
- sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${2} WITH GRANT OPTION;"
+ if [ $# -gt 1 ]; then
+ sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;"
fi
ynh_psql_execute_as_root --sql="$sql"
From b1b14a399d0587258ecef91c8ac3dab2203cf6e8 Mon Sep 17 00:00:00 2001
From: Kayou
Date: Thu, 21 Feb 2019 01:03:21 +0100
Subject: [PATCH 064/199] fix ynh_psql_database_exists
---
data/helpers.d/psql | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index e427582d6..8051736c1 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -154,8 +154,8 @@ ynh_psql_user_exists() {
# | arg: -d, --database - the database for which to check existence
ynh_psql_database_exists() {
# Declare an array to define the options of this helper.
- local legacy_args=u
- declare -Ar args_array=([u]=database=)
+ local legacy_args=d
+ declare -Ar args_array=([d]=database=)
local database
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
From 95dd4303344aead0603dbfad765850820a37c4ce Mon Sep 17 00:00:00 2001
From: Kayou
Date: Thu, 21 Feb 2019 01:06:38 +0100
Subject: [PATCH 065/199] ynh_psql_create_db take only 2 arguments
---
data/helpers.d/psql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index 8051736c1..f5e076d4f 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -204,7 +204,7 @@ ynh_psql_setup_db() {
ynh_psql_create_user "$db_user" "$db_pwd"
fi
- ynh_psql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database
+ ynh_psql_create_db "$db_name" "$db_user" # Create the database
ynh_app_setting_set --app=$app --key=psqlpwd --value=$db_pwd # Store the password in the app's config
}
From 49ec93a9c57f5a3fd1c734c8da09967e2d1809ab Mon Sep 17 00:00:00 2001
From: Kayou
Date: Thu, 21 Feb 2019 01:31:31 +0100
Subject: [PATCH 066/199] default argument for a optional argument
---
data/helpers.d/psql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index f5e076d4f..47804f585 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -72,7 +72,7 @@ ynh_psql_execute_file_as_root() {
# | arg: user - the user to grant privilegies
ynh_psql_create_db() {
local db=$1
- local user=$2
+ local user=${2:-}
local sql="CREATE DATABASE ${db};"
From c24d45beff554a7de94b0e9dcc560d0c66896a4d Mon Sep 17 00:00:00 2001
From: Kayou
Date: Thu, 21 Feb 2019 01:39:15 +0100
Subject: [PATCH 067/199] remove false promises
---
data/helpers.d/psql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index 47804f585..e3c3bb96e 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -120,7 +120,7 @@ ynh_psql_dump_db() {
#
# [internal]
#
-# usage: ynh_psql_create_user user pwd [host]
+# usage: ynh_psql_create_user user pwd
# | arg: user - the user name to create
# | arg: pwd - the password to identify user by
ynh_psql_create_user() {
From 9aa6cb6ac5c23f1a5385d0bda513629a445bf8ee Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 21 Feb 2019 20:46:18 +0100
Subject: [PATCH 068/199] add hook to reconfigure nginx or ssh on settings
change
---
src/yunohost/settings.py | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 1d60c3a6a..96c73a79d 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -239,3 +239,14 @@ def _save_settings(settings, location=SETTINGS_PATH):
settings_fd.write(result)
except Exception as e:
raise YunohostError('global_settings_cant_write_settings', reason=e)
+
+@post_change_hook("security.ciphers.compatibility")
+def reconfigure_nginx(setting_name, old_value, new_value):
+ if old_value != new_value:
+ service_regen_conf("nginx")
+
+@post_change_hook("service.ssh.ciphers.compatibility")
+def reconfigure_ssh(setting_name, old_value, new_value):
+ if old_value != new_value:
+ service_regen_conf("ssh")
+
From ac250e2549974adc2a610756f9bea2f8404b27d5 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 21 Feb 2019 21:15:25 +0100
Subject: [PATCH 069/199] fix service_regen_conf syntax
---
src/yunohost/settings.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 96c73a79d..d19b0cba3 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -7,6 +7,7 @@ from collections import OrderedDict
from moulinette import m18n
from yunohost.utils.error import YunohostError
from moulinette.utils.log import getActionLogger
+from yunohost.service import service_regen_conf
logger = getActionLogger('yunohost.settings')
@@ -243,10 +244,10 @@ def _save_settings(settings, location=SETTINGS_PATH):
@post_change_hook("security.ciphers.compatibility")
def reconfigure_nginx(setting_name, old_value, new_value):
if old_value != new_value:
- service_regen_conf("nginx")
+ service_regen_conf(names=['nginx'], force=True)
@post_change_hook("service.ssh.ciphers.compatibility")
def reconfigure_ssh(setting_name, old_value, new_value):
if old_value != new_value:
- service_regen_conf("ssh")
+ service_regen_conf(names=['ssh'], force=True)
From d7f381518348cde6feb6be8a64c510745d35180f Mon Sep 17 00:00:00 2001
From: Kayou
Date: Fri, 22 Feb 2019 00:58:12 +0100
Subject: [PATCH 070/199] For your eyes
---
data/helpers.d/psql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index e3c3bb96e..1d992d268 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -77,7 +77,7 @@ ynh_psql_create_db() {
local sql="CREATE DATABASE ${db};"
# grant all privilegies to user
- if [ $# -gt 1 ]; then
+ if [ -n "$user" ]; then
sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;"
fi
From abc091911c717539cb259a9a353159ba590cb017 Mon Sep 17 00:00:00 2001
From: Kayou
Date: Fri, 22 Feb 2019 01:13:23 +0100
Subject: [PATCH 071/199] User ynh_replace_string, add postgresql in the admin
panel
---
data/helpers.d/psql | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index 1d992d268..324cfee83 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -252,8 +252,10 @@ ynh_psql_test_if_first_run() {
if [ -e /etc/postgresql/9.4/ ]; then
local pg_hba=/etc/postgresql/9.4/main/pg_hba.conf
+ local logfile=/var/log/postgresql/postgresql-9.4-main.log
elif [ -e /etc/postgresql/9.6/ ]; then
local pg_hba=/etc/postgresql/9.6/main/pg_hba.conf
+ local logfile=/var/log/postgresql/postgresql-9.6-main.log
else
ynh_die "postgresql shoud be 9.4 or 9.6"
fi
@@ -265,8 +267,11 @@ ynh_psql_test_if_first_run() {
# https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html#EXAMPLE-PG-HBA.CONF
# Note: we can't use peer since YunoHost create users with nologin
# See: https://github.com/YunoHost/yunohost/blob/unstable/data/helpers.d/user
- sed -i '/local\s*all\s*all\s*peer/i \
- local all all password' "$pg_hba"
+ ynh_replace_string --match_string="local\(\s*\)all\(\s*\)all\(\s*\)peer" --replace_string="local\1all\2all\3password" --target_file="$pg_hba"
+
+ # Advertise service in admin panel
+ yunohost service add postgresql --log "$logfile"
+
systemctl enable postgresql
systemctl reload postgresql
fi
From 283e01db8fa3c2322670f465427710cbbb300640 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Sun, 24 Feb 2019 01:58:33 +0100
Subject: [PATCH 072/199] Don't make a whole HTTP request every dyndns
update...
---
src/yunohost/dyndns.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/dyndns.py b/src/yunohost/dyndns.py
index 2f8d63135..53486241a 100644
--- a/src/yunohost/dyndns.py
+++ b/src/yunohost/dyndns.py
@@ -333,7 +333,8 @@ def _guess_current_dyndns_domain(dyn_host):
"""
# Retrieve the first registered domain
- for path in glob.iglob('/etc/yunohost/dyndns/K*.private'):
+ paths = list(glob.iglob('/etc/yunohost/dyndns/K*.private'))
+ for path in paths:
match = RE_DYNDNS_PRIVATE_KEY_MD5.match(path)
if not match:
match = RE_DYNDNS_PRIVATE_KEY_SHA512.match(path)
@@ -343,7 +344,9 @@ def _guess_current_dyndns_domain(dyn_host):
# Verify if domain is registered (i.e., if it's available, skip
# current domain beause that's not the one we want to update..)
- if _dyndns_available(dyn_host, _domain):
+ # If there's only 1 such key found, then avoid doing the request
+ # for nothing (that's very probably the one we want to find ...)
+ if len(paths) > 1 and _dyndns_available(dyn_host, _domain):
continue
else:
return (_domain, path)
From 3f8f328fae8967a6294495484c7c197e8497947d Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Sun, 24 Feb 2019 02:04:41 +0100
Subject: [PATCH 073/199] Delete the key if subscribing failed, to avoid
confusion later trying to detect registered domains
---
src/yunohost/dyndns.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/yunohost/dyndns.py b/src/yunohost/dyndns.py
index 53486241a..090ee3901 100644
--- a/src/yunohost/dyndns.py
+++ b/src/yunohost/dyndns.py
@@ -144,7 +144,8 @@ def dyndns_subscribe(operation_logger, subscribe_host="dyndns.yunohost.org", dom
'dnssec-keygen -a hmac-sha512 -b 512 -r /dev/urandom -n USER %s' % domain)
os.system('chmod 600 /etc/yunohost/dyndns/*.key /etc/yunohost/dyndns/*.private')
- key_file = glob.glob('/etc/yunohost/dyndns/*.key')[0]
+ private_file = glob.glob('/etc/yunohost/dyndns/*%s*.private' % domain)[0]
+ key_file = glob.glob('/etc/yunohost/dyndns/*%s*.key' % domain)[0]
with open(key_file) as f:
key = f.readline().strip().split(' ', 6)[-1]
@@ -153,8 +154,12 @@ def dyndns_subscribe(operation_logger, subscribe_host="dyndns.yunohost.org", dom
try:
r = requests.post('https://%s/key/%s?key_algo=hmac-sha512' % (subscribe_host, base64.b64encode(key)), data={'subdomain': domain}, timeout=30)
except requests.ConnectionError:
+ os.system("rm %s" % private_file)
+ os.system("rm %s" % key_file)
raise YunohostError('no_internet_connection')
if r.status_code != 201:
+ os.system("rm %s" % private_file)
+ os.system("rm %s" % key_file)
try:
error = json.loads(r.text)['error']
except:
From 9657387746137d0a4e1adfefd2757759325951a7 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Sun, 24 Feb 2019 02:10:24 +0100
Subject: [PATCH 074/199] Prevent calling dyndns_subscribe if already
subscribed
---
src/yunohost/dyndns.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/yunohost/dyndns.py b/src/yunohost/dyndns.py
index 090ee3901..36509b0e4 100644
--- a/src/yunohost/dyndns.py
+++ b/src/yunohost/dyndns.py
@@ -119,6 +119,9 @@ def dyndns_subscribe(operation_logger, subscribe_host="dyndns.yunohost.org", dom
subscribe_host -- Dynette HTTP API to subscribe to
"""
+ if len(glob.glob('/etc/yunohost/dyndns/*.key')) != 0 or os.path.exists('/etc/cron.d/yunohost-dyndns'):
+ raise YunohostError('domain_dyndns_already_subscribed')
+
if domain is None:
domain = _get_maindomain()
operation_logger.related_to.append(('domain', domain))
From f17f51f3f6de24c69eaf552209947a7414cb5b12 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Sun, 24 Feb 2019 03:32:14 +0100
Subject: [PATCH 075/199] Add ynh_app_setting helper to optimize app setting
interface
---
data/helpers.d/setting | 37 ++++++++++++++++++++++++++++++++++---
1 file changed, 34 insertions(+), 3 deletions(-)
diff --git a/data/helpers.d/setting b/data/helpers.d/setting
index 6f75f6c80..18a57780a 100644
--- a/data/helpers.d/setting
+++ b/data/helpers.d/setting
@@ -14,7 +14,7 @@ ynh_app_setting_get() {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
- sudo yunohost app setting "$app" "$key" --output-as plain --quiet
+ ynh_app_setting "get" "$app" "$key"
}
# Set an application setting
@@ -33,7 +33,7 @@ ynh_app_setting_set() {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
- sudo yunohost app setting "$app" "$key" --value="$value" --quiet
+ ynh_app_setting "set" "$app" "$key" "$value"
}
# Delete an application setting
@@ -50,5 +50,36 @@ ynh_app_setting_delete() {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
- sudo yunohost app setting -d "$app" "$key" --quiet
+ ynh_app_setting "delete" "$app" "$key"
+}
+
+# Small "hard-coded" interface to avoid calling "yunohost app" directly each
+# time dealing with a setting is needed (which may be so slow on ARM boards)
+#
+# [internal]
+#
+ynh_app_setting()
+{
+ ACTION="$1" APP="$2" KEY="$3" VALUE="$4" python - <
Date: Mon, 25 Feb 2019 01:23:05 +0100
Subject: [PATCH 076/199] Typo
---
locales/en.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/locales/en.json b/locales/en.json
index ac9091c19..a6d95ada1 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -211,7 +211,7 @@
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
"hook_exec_failed": "Script execution failed: {path:s}",
"hook_exec_not_terminated": "Script execution hasn\u2019t terminated: {path:s}",
- "hook_json_return_error": "Faild to read return from hook {path:s}. Error: {msg:s}",
+ "hook_json_return_error": "Failed to read return from hook {path:s}. Error: {msg:s}",
"hook_list_by_invalid": "Invalid property to list hook by",
"hook_name_unknown": "Unknown hook name '{name:s}'",
"installation_complete": "Installation complete",
From e7d322b68ccf6bb13e103ace8b1ed81543984f91 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Mon, 25 Feb 2019 18:29:46 +0100
Subject: [PATCH 077/199] don't enforce services reconfiguration generation
unless you don't want to keep user meodifications
---
src/yunohost/settings.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index cb87f67ac..916e8b8c3 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -286,9 +286,9 @@ def trigger_post_change_hook(setting_name, old_value, new_value):
@post_change_hook("security.ciphers.compatibility")
def reconfigure_nginx(setting_name, old_value, new_value):
if old_value != new_value:
- service_regen_conf(names=['nginx'], force=True)
+ service_regen_conf(names=['nginx'])
@post_change_hook("service.ssh.ciphers.compatibility")
def reconfigure_ssh(setting_name, old_value, new_value):
if old_value != new_value:
- service_regen_conf(names=['ssh'], force=True)
+ service_regen_conf(names=['ssh'])
From 873bf4ae370cf785c66db0028ca1ab5bc06340c0 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Mon, 25 Feb 2019 18:44:21 +0100
Subject: [PATCH 078/199] Add min version for all helpers
---
data/helpers.d/backend | 16 ++++++++++++++++
data/helpers.d/debug | 4 ++++
data/helpers.d/filesystem | 11 +++++++++++
data/helpers.d/getopts | 2 ++
data/helpers.d/ip | 3 +++
data/helpers.d/mysql | 24 ++++++++++++++++++++++++
data/helpers.d/network | 8 ++++++++
data/helpers.d/nodejs | 10 ++++++++++
data/helpers.d/package | 24 ++++++++++++++++++++++++
data/helpers.d/print | 27 +++++++++++++++++++++++++++
data/helpers.d/psql | 20 ++++++++++++++++++++
data/helpers.d/setting | 6 ++++++
data/helpers.d/string | 6 ++++++
data/helpers.d/system | 12 ++++++++++++
data/helpers.d/user | 12 ++++++++++++
data/helpers.d/utils | 8 ++++++++
16 files changed, 193 insertions(+)
diff --git a/data/helpers.d/backend b/data/helpers.d/backend
index e710da9c7..ac6f3e5de 100644
--- a/data/helpers.d/backend
+++ b/data/helpers.d/backend
@@ -14,6 +14,8 @@
#
# It's possible to use this helper several times, each config will be added to the same logrotate config file.
# Unless you use the option --non-append
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_use_logrotate () {
# Declare an array to define the options of this helper.
local legacy_args=lnuya
@@ -92,6 +94,8 @@ EOF
# Remove the app's logrotate config.
#
# usage: ynh_remove_logrotate
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_remove_logrotate () {
if [ -e "/etc/logrotate.d/$app" ]; then
sudo rm "/etc/logrotate.d/$app"
@@ -112,6 +116,7 @@ ynh_remove_logrotate () {
# __APP__ by $app
# __FINALPATH__ by $final_path
#
+# Requires YunoHost version 2.7.2 or higher.
ynh_add_systemd_config () {
# Declare an array to define the options of this helper.
local legacy_args=st
@@ -147,6 +152,7 @@ ynh_add_systemd_config () {
# usage: ynh_remove_systemd_config [--service=service]
# | arg: -s, --service - Service name (optionnal, $app by default)
#
+# Requires YunoHost version 2.7.2 or higher.
ynh_remove_systemd_config () {
# Declare an array to define the options of this helper.
local legacy_args=s
@@ -183,6 +189,7 @@ ynh_remove_systemd_config () {
# __PATH_2__ by $path_2
# __PORT_2__ by $port_2
#
+# Requires YunoHost version 2.7.2 or higher.
ynh_add_nginx_config () {
finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf"
local others_var=${1:-}
@@ -233,6 +240,8 @@ ynh_add_nginx_config () {
# Remove the dedicated nginx config
#
# usage: ynh_remove_nginx_config
+#
+# Requires YunoHost version 2.7.2 or higher.
ynh_remove_nginx_config () {
ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf"
sudo systemctl reload nginx
@@ -241,6 +250,8 @@ ynh_remove_nginx_config () {
# Create a dedicated php-fpm config
#
# usage: ynh_add_fpm_config
+#
+# Requires YunoHost version 2.7.2 or higher.
ynh_add_fpm_config () {
# Configure PHP-FPM 7.0 by default
local fpm_config_dir="/etc/php/7.0/fpm"
@@ -276,6 +287,8 @@ ynh_add_fpm_config () {
# Remove the dedicated php-fpm config
#
# usage: ynh_remove_fpm_config
+#
+# Requires YunoHost version 2.7.2 or higher.
ynh_remove_fpm_config () {
local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service)
@@ -350,6 +363,7 @@ ynh_remove_fpm_config () {
# To validate your regex you can test with this command:
# fail2ban-regex /var/log/YOUR_LOG_FILE_PATH /etc/fail2ban/filter.d/YOUR_APP.conf
#
+# Requires YunoHost version 3.?.? or higher.
ynh_add_fail2ban_config () {
# Declare an array to define the options of this helper.
declare -Ar args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=)
@@ -429,6 +443,8 @@ EOF
# Remove the dedicated fail2ban config (jail and filter conf files)
#
# usage: ynh_remove_fail2ban_config
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_remove_fail2ban_config () {
ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf"
ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf"
diff --git a/data/helpers.d/debug b/data/helpers.d/debug
index a8b7c8d69..ea20ffc1a 100644
--- a/data/helpers.d/debug
+++ b/data/helpers.d/debug
@@ -5,6 +5,8 @@
# usage: ynh_debug [--message=message] [--trace=1/0]
# | arg: -m, --message= - The text to print
# | arg: -t, --trace= - Turn on or off the trace of the script. Usefull to trace nonly a small part of a script.
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_debug () {
# Disable set xtrace for the helper itself, to not pollute the debug log
set +x
@@ -54,6 +56,8 @@ ynh_debug () {
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_debug_exec () {
ynh_debug --message="$(eval $@)"
}
diff --git a/data/helpers.d/filesystem b/data/helpers.d/filesystem
index 10123dea4..6fb6347a6 100644
--- a/data/helpers.d/filesystem
+++ b/data/helpers.d/filesystem
@@ -46,6 +46,7 @@ CAN_BIND=${CAN_BIND:-1}
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "/conf/"
# # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf"
#
+# Requires YunoHost version 2.4.0 or higher.
ynh_backup() {
# TODO find a way to avoid injection by file strange naming !
@@ -158,6 +159,7 @@ ynh_backup() {
#
# usage: ynh_restore
#
+# Requires YunoHost version 2.6.4 or higher.
ynh_restore () {
# Deduce the relative path of $YNH_CWD
local REL_DIR="${YNH_CWD#$YNH_BACKUP_DIR/}"
@@ -219,6 +221,7 @@ with open(sys.argv[1], 'r') as backup_file:
# # DON'T GIVE THE ARCHIVE PATH:
# ynh_restore_file "conf/nginx.conf"
#
+# Requires YunoHost version 2.6.4 or higher.
ynh_restore_file () {
# Declare an array to define the options of this helper.
local legacy_args=odm
@@ -313,6 +316,8 @@ properly with chmod/chown." >&2
#
# usage: ynh_store_file_checksum --file=file
# | arg: -f, --file - The file on which the checksum will performed, then stored.
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_store_file_checksum () {
# Declare an array to define the options of this helper.
local legacy_args=f
@@ -345,6 +350,8 @@ ynh_store_file_checksum () {
# | arg: -f, --file - The file on which the checksum test will be perfomed.
#
# | ret: Return the name a the backup file, or nothing
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_backup_if_checksum_is_different () {
# Declare an array to define the options of this helper.
local legacy_args=f
@@ -376,6 +383,8 @@ ynh_backup_if_checksum_is_different () {
#
# usage: ynh_remove_file_checksum file
# | arg: -f, --file= - The file for which the checksum will be deleted
+#
+# Requires YunoHost version 3.3.1 or higher.
ynh_delete_file_checksum () {
# Declare an array to define the options of this helper.
local legacy_args=f
@@ -392,6 +401,8 @@ ynh_delete_file_checksum () {
#
# usage: ynh_secure_remove --file=path_to_remove
# | arg: -f, --file - File or directory to remove
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_secure_remove () {
# Declare an array to define the options of this helper.
local legacy_args=f
diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts
index 7055325f1..f89784578 100644
--- a/data/helpers.d/getopts
+++ b/data/helpers.d/getopts
@@ -43,6 +43,8 @@
# To keep a retrocompatibility, a package can still call a helper, using getopts, with positional arguments.
# The "legacy mode" will manage the positional arguments and fill the variable in the same order than they are given in $args_array.
# e.g. for `my_helper "val1" val2`, arg1 will be filled with val1, and arg2 with val2.
+#
+# Requires YunoHost version 3.2.2 or higher.
ynh_handle_getopts_args () {
# Manage arguments only if there's some provided
set +x
diff --git a/data/helpers.d/ip b/data/helpers.d/ip
index c50d8be73..2ca4053d9 100644
--- a/data/helpers.d/ip
+++ b/data/helpers.d/ip
@@ -7,6 +7,7 @@
#
# example: ynh_validate_ip 4 111.222.333.444
#
+# Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip()
{
# http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298
@@ -40,6 +41,7 @@ EOF
# usage: ynh_validate_ip4 --ip_address=ip_address
# | ret: 0 for valid ipv4 addresses, 1 otherwise
#
+# Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip4()
{
# Declare an array to define the options of this helper.
@@ -60,6 +62,7 @@ ynh_validate_ip4()
# usage: ynh_validate_ip6 --ip_address=ip_address
# | ret: 0 for valid ipv6 addresses, 1 otherwise
#
+# Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip6()
{
# Declare an array to define the options of this helper.
diff --git a/data/helpers.d/mysql b/data/helpers.d/mysql
index fa1a61dab..313b7a245 100644
--- a/data/helpers.d/mysql
+++ b/data/helpers.d/mysql
@@ -11,6 +11,8 @@ MYSQL_ROOT_PWD_FILE=/etc/yunohost/mysql
# | arg: -u, --user - the user name to connect as
# | arg: -p, --password - the user password
# | arg: -d, --database - the database to connect to
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_connect_as() {
# Declare an array to define the options of this helper.
local legacy_args=upd
@@ -30,6 +32,8 @@ ynh_mysql_connect_as() {
# usage: ynh_mysql_execute_as_root --sql=sql [--database=database]
# | arg: -s, --sql - the SQL command to execute
# | arg: -d, --database - the database to connect to
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_execute_as_root() {
# Declare an array to define the options of this helper.
local legacy_args=sd
@@ -49,6 +53,8 @@ ynh_mysql_execute_as_root() {
# usage: ynh_mysql_execute_file_as_root --file=file [--database=database]
# | arg: -f, --file - the file containing SQL commands
# | arg: -d, --database - the database to connect to
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_execute_file_as_root() {
# Declare an array to define the options of this helper.
local legacy_args=fd
@@ -71,6 +77,8 @@ ynh_mysql_execute_file_as_root() {
# | arg: db - the database name to create
# | arg: user - the user to grant privilegies
# | arg: pwd - the password to identify user by
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_create_db() {
local db=$1
@@ -95,6 +103,8 @@ ynh_mysql_create_db() {
#
# usage: ynh_mysql_drop_db db
# | arg: db - the database name to drop
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_drop_db() {
ynh_mysql_execute_as_root --sql="DROP DATABASE ${1};"
}
@@ -106,6 +116,8 @@ ynh_mysql_drop_db() {
# usage: ynh_mysql_dump_db --database=database
# | arg: -d, --database - the database name to dump
# | ret: the mysqldump output
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_dump_db() {
# Declare an array to define the options of this helper.
local legacy_args=d
@@ -124,6 +136,8 @@ ynh_mysql_dump_db() {
# usage: ynh_mysql_create_user user pwd [host]
# | arg: user - the user name to create
# | arg: pwd - the password to identify user by
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_create_user() {
ynh_mysql_execute_as_root \
--sql="CREATE USER '${1}'@'localhost' IDENTIFIED BY '${2}';"
@@ -133,6 +147,8 @@ ynh_mysql_create_user() {
#
# usage: ynh_mysql_user_exists --user=user
# | arg: -u, --user - the user for which to check existence
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_user_exists()
{
# Declare an array to define the options of this helper.
@@ -156,6 +172,8 @@ ynh_mysql_user_exists()
#
# usage: ynh_mysql_drop_user user
# | arg: user - the user name to drop
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_drop_user() {
ynh_mysql_execute_as_root --sql="DROP USER '${1}'@'localhost';"
}
@@ -169,6 +187,8 @@ ynh_mysql_drop_user() {
# | arg: -u, --db_user - Owner of the database
# | arg: -n, --db_name - Name of the database
# | arg: -p, --db_pwd - Password of the database. If not given, a password will be generated
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_mysql_setup_db () {
# Declare an array to define the options of this helper.
local legacy_args=unp
@@ -192,6 +212,8 @@ ynh_mysql_setup_db () {
# usage: ynh_mysql_remove_db --db_user=user --db_name=name
# | arg: -u, --db_user - Owner of the database
# | arg: -n, --db_name - Name of the database
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_mysql_remove_db () {
# Declare an array to define the options of this helper.
local legacy_args=un
@@ -223,6 +245,8 @@ ynh_mysql_remove_db () {
# usage: ynh_sanitize_dbid --db_name=name
# | arg: -n, --db_name - name to correct/sanitize
# | ret: the corrected name
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_sanitize_dbid () {
# Declare an array to define the options of this helper.
local legacy_args=n
diff --git a/data/helpers.d/network b/data/helpers.d/network
index a765d6346..8812f8f39 100644
--- a/data/helpers.d/network
+++ b/data/helpers.d/network
@@ -12,6 +12,8 @@
#
# usage: ynh_normalize_url_path --path_url=path_to_normalize
# | arg: -p, --path_url - URL path to normalize before using it
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_normalize_url_path () {
# Declare an array to define the options of this helper.
local legacy_args=p
@@ -36,6 +38,8 @@ ynh_normalize_url_path () {
#
# usage: ynh_find_port --port=begin_port
# | arg: -p, --port - port to start to search
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_find_port () {
# Declare an array to define the options of this helper.
local legacy_args=p
@@ -59,6 +63,8 @@ ynh_find_port () {
# usage: ynh_webpath_available --domain=domain --path_url=path
# | arg: -d, --domain - the domain/host of the url
# | arg: -p, --path_url - the web path to check the availability of
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_webpath_available () {
# Declare an array to define the options of this helper.
local legacy_args=dp
@@ -79,6 +85,8 @@ ynh_webpath_available () {
# | arg: -a, --app - the app for which the domain should be registered
# | arg: -d, --domain - the domain/host of the web path
# | arg: -p, --path_url - the web path to be registered
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_webpath_register () {
# Declare an array to define the options of this helper.
local legacy_args=adp
diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs
index 61a1414ef..34583328d 100644
--- a/data/helpers.d/nodejs
+++ b/data/helpers.d/nodejs
@@ -10,6 +10,8 @@ export N_PREFIX="$n_install_dir"
# [internal]
#
# usage: ynh_install_n
+#
+# Requires YunoHost version 2.7.12 or higher.
ynh_install_n () {
echo "Installation of N - Node.js version management" >&2
# Build an app.src for n
@@ -36,6 +38,8 @@ SOURCE_SUM=2ba3c9d4dd3c7e38885b37e02337906a1ee91febe6d5c9159d89a9050f2eea8f" > "
# That's means it has to be added to any systemd script.
#
# usage: ynh_use_nodejs
+#
+# Requires YunoHost version 2.7.12 or higher.
ynh_use_nodejs () {
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
@@ -59,6 +63,8 @@ ynh_use_nodejs () {
# | arg: -n, --nodejs_version - Version of node to install.
# If possible, prefer to use major version number (e.g. 8 instead of 8.10.0).
# The crontab will handle the update of minor versions when needed.
+#
+# Requires YunoHost version 2.7.12 or higher.
ynh_install_nodejs () {
# Use n, https://github.com/tj/n to manage the nodejs versions
@@ -135,6 +141,8 @@ ynh_install_nodejs () {
# If no other app uses node, n will be also removed.
#
# usage: ynh_remove_nodejs
+#
+# Requires YunoHost version 2.7.12 or higher.
ynh_remove_nodejs () {
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
@@ -164,6 +172,8 @@ ynh_remove_nodejs () {
# This cron will check and update all minor node versions used by your apps.
#
# usage: ynh_cron_upgrade_node
+#
+# Requires YunoHost version 2.7.12 or higher.
ynh_cron_upgrade_node () {
# Build the update script
cat > "$n_install_dir/node_update.sh" << EOF
diff --git a/data/helpers.d/package b/data/helpers.d/package
index 3924fc14e..75323521d 100644
--- a/data/helpers.d/package
+++ b/data/helpers.d/package
@@ -5,6 +5,8 @@
# [internal]
#
# usage: ynh_wait_dpkg_free
+#
+# Requires YunoHost version 3.3.1 or higher.
ynh_wait_dpkg_free() {
local try
# With seq 1 17, timeout will be almost 30 minutes
@@ -44,6 +46,8 @@ ynh_wait_dpkg_free() {
#
# usage: ynh_package_is_installed --package=name
# | arg: -p, --package - the package name to check
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_is_installed() {
# Declare an array to define the options of this helper.
local legacy_args=p
@@ -64,6 +68,8 @@ ynh_package_is_installed() {
# usage: ynh_package_version --package=name
# | arg: -p, --package - the package name to get version
# | ret: the version or an empty string
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_version() {
# Declare an array to define the options of this helper.
local legacy_args=p
@@ -84,6 +90,8 @@ ynh_package_version() {
# [internal]
#
# usage: ynh_apt update
+#
+# Requires YunoHost version 2.4.0.3 or higher.
ynh_apt() {
ynh_wait_dpkg_free
DEBIAN_FRONTEND=noninteractive apt-get -y $@
@@ -92,6 +100,8 @@ ynh_apt() {
# Update package index files
#
# usage: ynh_package_update
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_update() {
ynh_apt update
}
@@ -100,6 +110,8 @@ ynh_package_update() {
#
# usage: ynh_package_install name [name [...]]
# | arg: name - the package name to install
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_install() {
ynh_apt --no-remove -o Dpkg::Options::=--force-confdef \
-o Dpkg::Options::=--force-confold install $@
@@ -109,6 +121,8 @@ ynh_package_install() {
#
# usage: ynh_package_remove name [name [...]]
# | arg: name - the package name to remove
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_remove() {
ynh_apt remove $@
}
@@ -117,6 +131,8 @@ ynh_package_remove() {
#
# usage: ynh_package_autoremove name [name [...]]
# | arg: name - the package name to remove
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_autoremove() {
ynh_apt autoremove $@
}
@@ -125,6 +141,8 @@ ynh_package_autoremove() {
#
# usage: ynh_package_autopurge name [name [...]]
# | arg: name - the package name to autoremove and purge
+#
+# Requires YunoHost version 2.7.2 or higher.
ynh_package_autopurge() {
ynh_apt autoremove --purge $@
}
@@ -139,6 +157,8 @@ ynh_package_autopurge() {
#
# usage: ynh_package_install_from_equivs controlfile
# | arg: controlfile - path of the equivs control file
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_install_from_equivs () {
local controlfile=$1
@@ -181,6 +201,8 @@ ynh_package_install_from_equivs () {
# You can give a choice between some package with this syntax : "dep1|dep2"
# Example : ynh_install_app_dependencies dep1 dep2 "dep3|dep4|dep5"
# This mean in the dependence tree : dep1 & dep2 & (dep3 | dep4 | dep5)
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_install_app_dependencies () {
local dependencies=$@
local dependencies=${dependencies// /, }
@@ -217,6 +239,8 @@ EOF
# Dependencies will removed only if no other package need them.
#
# usage: ynh_remove_app_dependencies
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_remove_app_dependencies () {
local dep_app=${app//_/-} # Replace all '_' by '-'
ynh_package_autopurge ${dep_app}-ynh-deps # Remove the fake package and its dependencies if they not still used.
diff --git a/data/helpers.d/print b/data/helpers.d/print
index 7f37021ae..6e7b2b1d7 100644
--- a/data/helpers.d/print
+++ b/data/helpers.d/print
@@ -2,6 +2,8 @@
# Print a message to stderr and exit
# usage: ynh_die --message=MSG [--ret_code=RETCODE]
+#
+# Requires YunoHost version 2.4.0 or higher.
ynh_die() {
# Declare an array to define the options of this helper.
local legacy_args=mc
@@ -18,6 +20,8 @@ ynh_die() {
# Display a message in the 'INFO' logging category
#
# usage: ynh_print_info --message="Some message"
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_print_info() {
# Declare an array to define the options of this helper.
local legacy_args=m
@@ -37,6 +41,8 @@ ynh_print_info() {
#
# Simply duplicate the log, execute the yunohost command and replace the log without the result of this command
# It's a very badly hack...
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_no_log() {
local ynh_cli_log=/var/log/yunohost/yunohost-cli.log
sudo cp -a ${ynh_cli_log} ${ynh_cli_log}-move
@@ -50,6 +56,7 @@ ynh_no_log() {
#
# [internal]
#
+# Requires YunoHost version 3.2.0 or higher.
ynh_print_log () {
echo -e "${1}"
}
@@ -58,6 +65,8 @@ ynh_print_log () {
#
# usage: ynh_print_warn --message="Text to print"
# | arg: -m, --message - The text to print
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_print_warn () {
# Declare an array to define the options of this helper.
local legacy_args=m
@@ -73,6 +82,8 @@ ynh_print_warn () {
#
# usage: ynh_print_err --message="Text to print"
# | arg: -m, --message - The text to print
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_print_err () {
# Declare an array to define the options of this helper.
local legacy_args=m
@@ -91,6 +102,8 @@ ynh_print_err () {
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_exec_err () {
ynh_print_err "$(eval $@)"
}
@@ -102,6 +115,8 @@ ynh_exec_err () {
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_exec_warn () {
ynh_print_warn "$(eval $@)"
}
@@ -113,6 +128,8 @@ ynh_exec_warn () {
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_exec_warn_less () {
eval $@ 2>&1
}
@@ -124,6 +141,8 @@ ynh_exec_warn_less () {
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_exec_quiet () {
eval $@ > /dev/null
}
@@ -135,6 +154,8 @@ ynh_exec_quiet () {
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_exec_fully_quiet () {
eval $@ > /dev/null 2>&1
}
@@ -143,6 +164,8 @@ ynh_exec_fully_quiet () {
#
# usage: ynh_print_OFF
# WARNING: You should be careful with this helper, and never forget to use ynh_print_ON as soon as possible to restore the logging.
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_print_OFF () {
set +x
}
@@ -150,6 +173,8 @@ ynh_print_OFF () {
# Restore the logging after ynh_print_OFF
#
# usage: ynh_print_ON
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_print_ON () {
set -x
# Print an echo only for the log, to be able to know that ynh_print_ON has been called.
@@ -163,6 +188,8 @@ ynh_print_ON () {
# | arg: -w, --weight= - The weight for this progression. This value is 1 by default. Use a bigger value for a longer part of the script.
# | arg: -t, --time= - Print the execution time since the last call to this helper. Especially usefull to define weights.
# | arg: -l, --last= - Use for the last call of the helper, to fill te progression bar.
+#
+# Requires YunoHost version 3.?.? or higher.
increment_progression=0
previous_weight=0
# Define base_time when the file is sourced
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index 2ef13482a..70ea58af4 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -2,6 +2,8 @@
# Please always call this script in install and restore scripts
#
# usage: ynh_psql_test_if_first_run
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_test_if_first_run() {
if [ -f /etc/yunohost/psql ];
then
@@ -43,6 +45,8 @@ ynh_psql_test_if_first_run() {
# | arg: user - the user name to connect as
# | arg: pwd - the user password
# | arg: db - the database to connect to
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_connect_as() {
local user="$1"
local pwd="$2"
@@ -54,6 +58,8 @@ ynh_psql_connect_as() {
#
# usage: ynh_psql_execute_as_root sql [db]
# | arg: sql - the SQL command to execute
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_execute_as_root () {
local sql="$1"
sudo --login --user=postgres psql <<< "$sql"
@@ -64,6 +70,8 @@ ynh_psql_execute_as_root () {
# usage: ynh_psql_execute_file_as_root file [db]
# | arg: file - the file containing SQL commands
# | arg: db - the database to connect to
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_execute_file_as_root() {
local file="$1"
local db="$2"
@@ -79,6 +87,8 @@ ynh_psql_execute_file_as_root() {
# | arg: user - Owner of the database
# | arg: name - Name of the database
# | arg: pwd - Password of the database. If not given, a password will be generated
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_setup_db () {
local db_user="$1"
local db_name="$2"
@@ -95,6 +105,8 @@ ynh_psql_setup_db () {
# | arg: db - the database name to create
# | arg: user - the user to grant privilegies
# | arg: pwd - the user password
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_create_db() {
local db="$1"
local user="$2"
@@ -108,6 +120,8 @@ ynh_psql_create_db() {
# usage: ynh_psql_drop_db db
# | arg: db - the database name to drop
# | arg: user - the user to drop
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_remove_db() {
local db="$1"
local user="$2"
@@ -122,6 +136,8 @@ ynh_psql_remove_db() {
# usage: ynh_psql_dump_db db
# | arg: db - the database name to dump
# | ret: the psqldump output
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_dump_db() {
local db="$1"
sudo --login --user=postgres pg_dump "$db"
@@ -132,6 +148,8 @@ ynh_psql_dump_db() {
#
# usage: ynh_psql_create_user user pwd [host]
# | arg: user - the user name to create
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_create_user() {
local user="$1"
local pwd="$2"
@@ -142,6 +160,8 @@ ynh_psql_create_user() {
#
# usage: ynh_psql_drop_user user
# | arg: user - the user name to drop
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_drop_user() {
local user="$1"
sudo --login --user=postgres dropuser "$user"
diff --git a/data/helpers.d/setting b/data/helpers.d/setting
index 6f75f6c80..0c3698061 100644
--- a/data/helpers.d/setting
+++ b/data/helpers.d/setting
@@ -5,6 +5,8 @@
# usage: ynh_app_setting_get --app=app --key=key
# | arg: -a, --app - the application id
# | arg: -k, --key - the setting to get
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_app_setting_get() {
# Declare an array to define the options of this helper.
local legacy_args=ak
@@ -23,6 +25,8 @@ ynh_app_setting_get() {
# | arg: -a, --app - the application id
# | arg: -k, --key - the setting name to set
# | arg: -v, --value - the setting value to set
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_app_setting_set() {
# Declare an array to define the options of this helper.
local legacy_args=akv
@@ -41,6 +45,8 @@ ynh_app_setting_set() {
# usage: ynh_app_setting_delete --app=app --key=key
# | arg: -a, --app - the application id
# | arg: -k, --key - the setting to delete
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_app_setting_delete() {
# Declare an array to define the options of this helper.
local legacy_args=ak
diff --git a/data/helpers.d/string b/data/helpers.d/string
index 739757d43..52eede872 100644
--- a/data/helpers.d/string
+++ b/data/helpers.d/string
@@ -6,6 +6,8 @@
#
# usage: ynh_string_random [--length=string_length]
# | arg: -l, --length - the string length to generate (default: 24)
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_string_random() {
# Declare an array to define the options of this helper.
local legacy_args=l
@@ -30,6 +32,8 @@ ynh_string_random() {
# As this helper is based on sed command, regular expressions and
# references to sub-expressions can be used
# (see sed manual page for more information)
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_replace_string () {
# Declare an array to define the options of this helper.
local legacy_args=mrf
@@ -57,6 +61,8 @@ ynh_replace_string () {
#
# This helper will use ynh_replace_string, but as you can use special
# characters, you can't use some regular expressions and sub-expressions.
+#
+# Requires YunoHost version 2.7.7 or higher.
ynh_replace_special_string () {
# Declare an array to define the options of this helper.
local legacy_args=mrf
diff --git a/data/helpers.d/system b/data/helpers.d/system
index 9a4219e11..fd5b21435 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -16,6 +16,7 @@
#
# It prints a warning to inform that the script was failed, and execute the ynh_clean_setup function if used in the app script
#
+# Requires YunoHost version 2.6.4 or higher.
ynh_exit_properly () {
local exit_code=$?
if [ "$exit_code" -eq 0 ]; then
@@ -43,6 +44,7 @@ ynh_exit_properly () {
# immediately and a call to `ynh_clean_setup` is triggered if it has been
# defined by your script.
#
+# Requires YunoHost version 2.6.4 or higher.
ynh_abort_if_errors () {
set -eu # Exit if a command fail, and if a variable is used unset.
trap ynh_exit_properly EXIT # Capturing exit signals on shell script
@@ -52,6 +54,8 @@ ynh_abort_if_errors () {
#
# usage: ynh_get_debian_release
# | ret: The Debian release codename (i.e. jessie, stretch, ...)
+#
+# Requires YunoHost version 2.7.12 or higher.
ynh_get_debian_release () {
echo $(lsb_release --codename --short)
}
@@ -61,6 +65,8 @@ ynh_get_debian_release () {
# usage: ynh_read_manifest manifest key
# | arg: -m, --manifest= - Path of the manifest to read
# | arg: -k, --key= - Name of the key to find
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_read_manifest () {
# Declare an array to define the options of this helper.
declare -Ar args_array=( [m]=manifest= [k]=manifest_key= )
@@ -85,6 +91,8 @@ ynh_read_manifest () {
#
# usage: ynh_app_upstream_version [-m manifest]
# | arg: -m, --manifest= - Path of the manifest to read
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_app_upstream_version () {
declare -Ar args_array=( [m]=manifest= )
local manifest
@@ -104,6 +112,8 @@ ynh_app_upstream_version () {
#
# usage: ynh_app_package_version [-m manifest]
# | arg: -m, --manifest= - Path of the manifest to read
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_app_package_version () {
declare -Ar args_array=( [m]=manifest= )
local manifest
@@ -129,6 +139,8 @@ ynh_app_package_version () {
# example: sudo YNH_FORCE_UPGRADE=1 yunohost app upgrade MyApp
#
# usage: ynh_check_app_version_changed
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_check_app_version_changed () {
local force_upgrade=${YNH_FORCE_UPGRADE:-0}
local package_check=${PACKAGE_CHECK_EXEC:-0}
diff --git a/data/helpers.d/user b/data/helpers.d/user
index d716bf03b..f19739993 100644
--- a/data/helpers.d/user
+++ b/data/helpers.d/user
@@ -6,6 +6,8 @@
#
# usage: ynh_user_exists --username=username
# | arg: -u, --username - the username to check
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_user_exists() {
# Declare an array to define the options of this helper.
local legacy_args=u
@@ -25,6 +27,8 @@ ynh_user_exists() {
# | arg: -u, --username - the username to retrieve info from
# | arg: -k, --key - the key to retrieve
# | ret: string - the key's value
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_user_get_info() {
# Declare an array to define the options of this helper.
local legacy_args=uk
@@ -43,6 +47,8 @@ ynh_user_get_info() {
#
# usage: ynh_user_list
# | ret: string - one username per line
+#
+# Requires YunoHost version 2.4.0 or higher.
ynh_user_list() {
sudo yunohost user list --output-as plain --quiet \
| awk '/^##username$/{getline; print}'
@@ -52,6 +58,8 @@ ynh_user_list() {
#
# usage: ynh_system_user_exists --username=username
# | arg: -u, --username - the username to check
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_system_user_exists() {
# Declare an array to define the options of this helper.
local legacy_args=u
@@ -76,6 +84,8 @@ ynh_system_user_exists() {
# | arg: -h, --home_dir - Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home
# | arg: -s, --use_shell - Create a user using the default login shell if present.
# If this argument is omitted, the user will be created with /usr/sbin/nologin shell
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_system_user_create () {
# Declare an array to define the options of this helper.
local legacy_args=uhs
@@ -108,6 +118,8 @@ ynh_system_user_create () {
#
# usage: ynh_system_user_delete --username=user_name
# | arg: -u, --username - Name of the system user that will be create
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_system_user_delete () {
# Declare an array to define the options of this helper.
local legacy_args=u
diff --git a/data/helpers.d/utils b/data/helpers.d/utils
index 5ba2946a2..5f5e61015 100644
--- a/data/helpers.d/utils
+++ b/data/helpers.d/utils
@@ -6,6 +6,8 @@
#
# usage: ynh_get_plain_key key [subkey [subsubkey ...]]
# | ret: string - the key's value
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_get_plain_key() {
local prefix="#"
local founded=0
@@ -36,6 +38,7 @@ ynh_get_plain_key() {
# }
# ynh_abort_if_errors
#
+# Requires YunoHost version 2.7.2 or higher.
ynh_restore_upgradebackup () {
echo "Upgrade failed." >&2
local app_bck=${app//_/-} # Replace all '_' by '-'
@@ -67,6 +70,7 @@ ynh_restore_upgradebackup () {
# }
# ynh_abort_if_errors
#
+# Requires YunoHost version 2.7.2 or higher.
ynh_backup_before_upgrade () {
if [ ! -e "/etc/yunohost/apps/$app/scripts/backup" ]
then
@@ -150,6 +154,8 @@ ynh_backup_before_upgrade () {
# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id]
# | arg: -d, --dest_dir - Directory where to setup sources
# | arg: -s, --source_id - Name of the app, if the package contains more than one app
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_setup_source () {
# Declare an array to define the options of this helper.
local legacy_args=ds
@@ -255,6 +261,8 @@ ynh_setup_source () {
# | arg: key1=value1 - (Optionnal) POST key and corresponding value
# | arg: key2=value2 - (Optionnal) Another POST key and corresponding value
# | arg: ... - (Optionnal) More POST keys and values
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_local_curl () {
# Define url of page to curl
local local_page=$(ynh_normalize_url_path $1)
From b3edc2a63ccf23c95d7e58f9b3b17635372686b9 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Tue, 26 Feb 2019 01:59:03 +0100
Subject: [PATCH 079/199] Fix ynh_add_fail2ban_config legacy mode
Merged as a micro decision
Fix https://github.com/YunoHost/issues/issues/1313
---
data/helpers.d/backend | 1 +
1 file changed, 1 insertion(+)
diff --git a/data/helpers.d/backend b/data/helpers.d/backend
index e710da9c7..1532601a8 100644
--- a/data/helpers.d/backend
+++ b/data/helpers.d/backend
@@ -352,6 +352,7 @@ ynh_remove_fpm_config () {
#
ynh_add_fail2ban_config () {
# Declare an array to define the options of this helper.
+ local legacy_args=lrmptv
declare -Ar args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=)
local logpath
local failregex
From b49eeddcf94ee4d733d10a9db657281d36648e8a Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 26 Feb 2019 02:20:41 +0100
Subject: [PATCH 080/199] Drunk commits were drunk
---
src/yunohost/app.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index e84187d6b..a622c0f24 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -593,12 +593,12 @@ def app_upgrade(auth, app=[], url=None, file=None):
apps = [app]
# Remove possible duplicates
- apps = [app for i,app in enumerate(apps) if apps not in L[:i]]
+ apps = [app for i,app in enumerate(apps) if apps not in apps[:i]]
if len(apps) == 0:
raise YunohostError('app_no_upgrade')
if len(apps) > 1:
- logger.info(m18n.n("app_upgrade_several_apps", apps=", ".join(app)))
+ logger.info(m18n.n("app_upgrade_several_apps", apps=", ".join(apps)))
for app_instance_name in apps:
logger.info(m18n.n('app_upgrade_app_name', app=app_instance_name))
From 366d8231eb7d29708e4dea7a243c210acaa11c3f Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 26 Feb 2019 02:29:18 +0100
Subject: [PATCH 081/199] Makes no sense to not show those messages only if
that's a user-specified list ...
---
src/yunohost/app.py | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index a622c0f24..a91ba61eb 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -583,12 +583,11 @@ def app_upgrade(auth, app=[], url=None, file=None):
not_upgraded_apps = []
apps = app
- user_specified_list = True
# If no app is specified, upgrade all apps
if not apps:
+ # FIXME : not sure what's supposed to happen if there is a url and a file but no apps...
if not url and not file:
apps = [app["id"] for app in app_list(installed=True)["apps"]]
- user_specified_list = False
elif not isinstance(app, list):
apps = [app]
@@ -618,8 +617,7 @@ def app_upgrade(auth, app=[], url=None, file=None):
elif app_dict["upgradable"] == "yes":
manifest, extracted_app_folder = _fetch_app_from_git(app_instance_name)
else:
- if user_specified_list:
- logger.success(m18n.n('app_already_up_to_date', app=app_instance_name))
+ logger.success(m18n.n('app_already_up_to_date', app=app_instance_name))
continue
# Check requirements
From 15b3733e2241cdc8322e19399827c2f65772399f Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 26 Feb 2019 02:34:02 +0100
Subject: [PATCH 082/199] Don't raise an exception in the middle of the loop,
that check can be done before
---
src/yunohost/app.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index a91ba61eb..be0bb5a55 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -594,6 +594,10 @@ def app_upgrade(auth, app=[], url=None, file=None):
# Remove possible duplicates
apps = [app for i,app in enumerate(apps) if apps not in apps[:i]]
+ # Abort if any of those app is in fact not installed..
+ for app in [app for app in apps if not _is_installed(app)]:
+ raise YunohostError('app_not_installed', app=app)
+
if len(apps) == 0:
raise YunohostError('app_no_upgrade')
if len(apps) > 1:
@@ -601,9 +605,6 @@ def app_upgrade(auth, app=[], url=None, file=None):
for app_instance_name in apps:
logger.info(m18n.n('app_upgrade_app_name', app=app_instance_name))
- installed = _is_installed(app_instance_name)
- if not installed:
- raise YunohostError('app_not_installed', app=app_instance_name)
app_dict = app_info(app_instance_name, raw=True)
From f51101152a04fd6672198d1712c0886d27a80cc7 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Tue, 26 Feb 2019 15:37:50 +0100
Subject: [PATCH 083/199] Missing }
---
data/helpers.d/system | 1 +
1 file changed, 1 insertion(+)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index 604cf7bc6..cc1dbbcc5 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -148,6 +148,7 @@ ynh_clean_check_starting () {
# Stop the execution of tail.
kill -s 15 $pid_tail 2>&1
ynh_secure_remove "$templog" 2>&1
+}
# Read the value of a key in a ynh manifest file
#
From e6f1845448c86c32a379353c8c0a70797135a52b Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 1 Mar 2019 01:40:52 +0100
Subject: [PATCH 084/199] Add -f to rm
---
src/yunohost/dyndns.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/yunohost/dyndns.py b/src/yunohost/dyndns.py
index 36509b0e4..ddc285e8d 100644
--- a/src/yunohost/dyndns.py
+++ b/src/yunohost/dyndns.py
@@ -157,12 +157,12 @@ def dyndns_subscribe(operation_logger, subscribe_host="dyndns.yunohost.org", dom
try:
r = requests.post('https://%s/key/%s?key_algo=hmac-sha512' % (subscribe_host, base64.b64encode(key)), data={'subdomain': domain}, timeout=30)
except requests.ConnectionError:
- os.system("rm %s" % private_file)
- os.system("rm %s" % key_file)
+ os.system("rm -f %s" % private_file)
+ os.system("rm -f %s" % key_file)
raise YunohostError('no_internet_connection')
if r.status_code != 201:
- os.system("rm %s" % private_file)
- os.system("rm %s" % key_file)
+ os.system("rm -f %s" % private_file)
+ os.system("rm -f %s" % key_file)
try:
error = json.loads(r.text)['error']
except:
From 4a8563ed9e86d4aaedc8b189373056b505a250b6 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 1 Mar 2019 01:43:16 +0100
Subject: [PATCH 085/199] Clarify the if case for 'get'
---
data/helpers.d/setting | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/data/helpers.d/setting b/data/helpers.d/setting
index 18a57780a..ccd2ac0a6 100644
--- a/data/helpers.d/setting
+++ b/data/helpers.d/setting
@@ -75,9 +75,11 @@ else:
if action == "delete":
if key in settings:
del settings[key]
- else:
+ elif action == "get":
if key in ['redirected_urls', 'redirected_regex']:
value = yaml.load(value)
+ else:
+ raise ValueError("action should either be get, set or delete")
settings[key] = value
with open(setting_file, "w") as f:
yaml.safe_dump(settings, f, default_flow_style=False)
From 078b9b90bc22c56fc78255ae5fc72bea9e0e5af5 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Sun, 3 Mar 2019 00:50:36 +0100
Subject: [PATCH 086/199] Drunk commits were made >.>
---
data/helpers.d/setting | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/setting b/data/helpers.d/setting
index ccd2ac0a6..fb833281a 100644
--- a/data/helpers.d/setting
+++ b/data/helpers.d/setting
@@ -75,12 +75,12 @@ else:
if action == "delete":
if key in settings:
del settings[key]
- elif action == "get":
+ elif action == "set":
if key in ['redirected_urls', 'redirected_regex']:
value = yaml.load(value)
+ settings[key] = value
else:
raise ValueError("action should either be get, set or delete")
- settings[key] = value
with open(setting_file, "w") as f:
yaml.safe_dump(settings, f, default_flow_style=False)
EOF
From 12c61eeb6507faddf902a0bdc9a7c13fbba2fdbe Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Sun, 3 Mar 2019 16:38:54 +0100
Subject: [PATCH 087/199] Use printers
---
data/helpers.d/system | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index cc1dbbcc5..f319f3f7b 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -106,10 +106,10 @@ ynh_systemd_action() {
fi
fi
- echo "${action^} the service $service_name" >&2
+ ynh_print_info --message="${action^} the service $service_name"
systemctl $action $service_name \
|| ( journalctl --no-pager --lines=$length -u $service_name >&2 \
- ; test -e "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2 \
+ ; test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2 \
; false )
# Start the timeout and try to find line_match
@@ -121,21 +121,20 @@ ynh_systemd_action() {
# Read the log until the sentence is found, that means the app finished to start. Or run until the timeout
if grep --quiet "$line_match" "$templog"
then
- echo "The service $service_name has correctly started." >&2
+ ynh_print_info --message="The service $service_name has correctly started."
break
fi
echo -n "." >&2
sleep 1
done
+ echo "" >&2
if [ $i -eq $timeout ]
then
- echo "The service $service_name didn't fully started before the timeout." >&2
- echo "Please find here an extract of the end of the log of the service $service_name:"
+ ynh_print_warn --message="The service $service_name didn't fully started before the timeout."
+ ynh_print_warn --message="Please find here an extract of the end of the log of the service $service_name:"
journalctl --no-pager --lines=$length -u $service_name >&2
- test -e "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2
+ test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2
fi
-
- echo ""
ynh_clean_check_starting
fi
}
From 58af343a84d2319b2a70b7e06133953c99d1af60 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Sun, 3 Mar 2019 17:25:07 +0100
Subject: [PATCH 088/199] Add warning about exec_* printers
---
data/helpers.d/print | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/data/helpers.d/print b/data/helpers.d/print
index 7f37021ae..b46192d87 100644
--- a/data/helpers.d/print
+++ b/data/helpers.d/print
@@ -89,6 +89,7 @@ ynh_print_err () {
# usage: ynh_exec_err command to execute
# usage: ynh_exec_err "command to execute | following command"
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
+# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
#
# | arg: command - command to execute
ynh_exec_err () {
@@ -100,6 +101,7 @@ ynh_exec_err () {
# usage: ynh_exec_warn command to execute
# usage: ynh_exec_warn "command to execute | following command"
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
+# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
#
# | arg: command - command to execute
ynh_exec_warn () {
@@ -111,6 +113,7 @@ ynh_exec_warn () {
# usage: ynh_exec_warn_less command to execute
# usage: ynh_exec_warn_less "command to execute | following command"
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
+# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
#
# | arg: command - command to execute
ynh_exec_warn_less () {
@@ -122,6 +125,7 @@ ynh_exec_warn_less () {
# usage: ynh_exec_quiet command to execute
# usage: ynh_exec_quiet "command to execute | following command"
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
+# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
#
# | arg: command - command to execute
ynh_exec_quiet () {
@@ -133,6 +137,7 @@ ynh_exec_quiet () {
# usage: ynh_exec_fully_quiet command to execute
# usage: ynh_exec_fully_quiet "command to execute | following command"
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
+# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
#
# | arg: command - command to execute
ynh_exec_fully_quiet () {
From 337a065b4a074a0a72b38d195875e1956136a804 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Sun, 3 Mar 2019 18:57:41 +0100
Subject: [PATCH 089/199] Print progression only after 3s
---
data/helpers.d/system | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index f319f3f7b..7061e261f 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -124,10 +124,17 @@ ynh_systemd_action() {
ynh_print_info --message="The service $service_name has correctly started."
break
fi
- echo -n "." >&2
+ if [ $i -eq 3 ]; then
+ echo -n "Please wait, the service $service_name is ${action}ing" >&2
+ fi
+ if [ $i -ge 3 ]; then
+ echo -n "." >&2
+ fi
sleep 1
done
- echo "" >&2
+ if [ $i -ge 3 ]; then
+ echo "" >&2
+ fi
if [ $i -eq $timeout ]
then
ynh_print_warn --message="The service $service_name didn't fully started before the timeout."
From 08e51f2680a82bf2fbf5a5de826e49cda86422ff Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Sun, 3 Mar 2019 18:58:38 +0100
Subject: [PATCH 090/199] Do not show errors about log not existing yet.
---
data/helpers.d/system | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index 7061e261f..bfc20cb33 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -100,7 +100,7 @@ ynh_systemd_action() {
local pid_tail=$!
else
# Read the specified log file
- tail -F -n0 "$log_path" > "$templog" &
+ tail -F -n0 "$log_path" > "$templog" 2>&1 &
# Get the PID of the tail command
local pid_tail=$!
fi
From e81e232fb216fb2f88cb381b42166bacea245b6e Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 4 Mar 2019 03:09:23 +0100
Subject: [PATCH 091/199] Add a check that some required services are up before
running install and upgrade
---
locales/en.json | 1 +
src/yunohost/app.py | 29 ++++++++++++++++++++++++++++-
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/locales/en.json b/locales/en.json
index 1157e0a54..f10542951 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -4,6 +4,7 @@
"admin_password": "Administration password",
"admin_password_change_failed": "Unable to change password",
"admin_password_changed": "The administration password has been changed",
+ "app_action_cannot_be_ran_because_required_services_down": "This app requires some services which are currently down. Before continuing, you should try to restart the following services (and possibly investigate why they are down) : {services}",
"app_already_installed": "{app:s} is already installed",
"app_already_installed_cant_change_url": "This app is already installed. The url cannot be changed just by this function. Look into `app changeurl` if it's available.",
"app_already_up_to_date": "{app:s} is already up to date",
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index be0bb5a55..4997727e3 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -42,7 +42,7 @@ from yunohost.utils.error import YunohostError
from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_json
-from yunohost.service import service_log, _run_service_command
+from yunohost.service import service_log, service_status, _run_service_command
from yunohost.utils import packages
from yunohost.log import is_unit_operation, OperationLogger
@@ -623,6 +623,7 @@ def app_upgrade(auth, app=[], url=None, file=None):
# Check requirements
_check_manifest_requirements(manifest, app_instance_name=app_instance_name)
+ _check_services_status_for_app(manifest.get("services", []))
app_setting_path = APPS_SETTING_PATH + '/' + app_instance_name
@@ -778,6 +779,7 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
# Check requirements
_check_manifest_requirements(manifest, app_id)
+ _check_services_status_for_app(manifest.get("services", []))
# Check if app can be forked
instance_number = _installed_instance_number(app_id, last=True) + 1
@@ -2574,6 +2576,31 @@ def unstable_apps():
return output
+def _check_services_status_for_app(services):
+
+ logger.debug("Checking that required services are up and running...")
+
+ # Some apps use php-fpm or php5-fpm which is now php7.0-fpm
+ def replace_alias(service):
+ if service in ["php-fpm", "php5-fpm"]:
+ return "php7.0-fpm"
+ else:
+ return service
+ services = [replace_alias(s) for s in services]
+
+ # We only check those, mostly to ignore "custom" services
+ # (added by apps) and because those are the most popular
+ # services
+ service_filter = ["nginx", "php7.0-fpm", "mysql", "postfix"]
+ services = [s for s in services if s in service_filter]
+
+ # List services currently down and raise an exception if any are found
+ faulty_services = [s for s, infos in service_status(services).items() if infos["active"] != "active"]
+ if faulty_services:
+ raise YunohostError('app_action_cannot_be_ran_because_required_services_down',
+ services=', '.join(faulty_services))
+
+
def _patch_php5(app_folder):
files_to_patch = []
From b8c5e9f1b6b0333c652ae89541baa80204ac054f Mon Sep 17 00:00:00 2001
From: Laurent Peuch
Date: Mon, 4 Mar 2019 02:59:14 +0100
Subject: [PATCH 092/199] [enh] allow 'display_text' ~fake~ argument in
manifest.json
---
src/yunohost/app.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index be0bb5a55..8561e2667 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -2202,6 +2202,11 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
if arg_type == 'boolean':
arg_default = 1 if arg_default else 0
+ # do not print for webadmin
+ if arg_type == 'display_text' and msettings.get('interface') != 'api':
+ print(arg["text"])
+ continue
+
# Attempt to retrieve argument value
if arg_name in args:
arg_value = args[arg_name]
From f37a6b43e1ab4e163877b6afdd3226009cfd70a2 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 4 Mar 2019 17:09:31 +0100
Subject: [PATCH 093/199] More general exception to handle other cases (e.g.
SSL errors, ...)
---
src/yunohost/dyndns.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/dyndns.py b/src/yunohost/dyndns.py
index ddc285e8d..2dadcef52 100644
--- a/src/yunohost/dyndns.py
+++ b/src/yunohost/dyndns.py
@@ -156,10 +156,10 @@ def dyndns_subscribe(operation_logger, subscribe_host="dyndns.yunohost.org", dom
# Send subscription
try:
r = requests.post('https://%s/key/%s?key_algo=hmac-sha512' % (subscribe_host, base64.b64encode(key)), data={'subdomain': domain}, timeout=30)
- except requests.ConnectionError:
+ except Exception as e:
os.system("rm -f %s" % private_file)
os.system("rm -f %s" % key_file)
- raise YunohostError('no_internet_connection')
+ raise YunohostError('dyndns_registration_failed', error=str(e))
if r.status_code != 201:
os.system("rm -f %s" % private_file)
os.system("rm -f %s" % key_file)
From 877fe506850b388807cfebf0e9d7561776ac2637 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 4 Mar 2019 17:21:57 +0100
Subject: [PATCH 094/199] Use a finally clause to avoid duplicated code
---
src/yunohost/hook.py | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/yunohost/hook.py b/src/yunohost/hook.py
index d9cad9c7a..961caf606 100644
--- a/src/yunohost/hook.py
+++ b/src/yunohost/hook.py
@@ -403,13 +403,11 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
else:
returnjson = {}
except Exception as e:
+ raise YunohostError('hook_json_return_error', path=path, msg=str(e))
+ finally:
+ stdreturndir = os.path.split(stdreturn)[0]
os.remove(stdreturn)
os.rmdir(stdreturndir)
- raise YunohostError('hook_json_return_error', path=path, msg=str(e))
-
- stdreturndir = os.path.split(stdreturn)[0]
- os.remove(stdreturn)
- os.rmdir(stdreturndir)
return returncode, returnjson
From c74bff31d12e08acc80f54f628e09ce8c16f7adc Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 4 Mar 2019 17:44:20 +0100
Subject: [PATCH 095/199] Fix listing of succeed/failed hook names
---
src/yunohost/service.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/yunohost/service.py b/src/yunohost/service.py
index 151a877b9..61274aaac 100644
--- a/src/yunohost/service.py
+++ b/src/yunohost/service.py
@@ -493,11 +493,14 @@ def service_regen_conf(operation_logger, names=[], with_diff=False, force=False,
pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call)
- # Update the services name
- names = {n: [p for p, c in v.items() if c['state'] == "failed"] for n, v in pre_result.items()}.keys()
+ # Keep only the hook names with at least one success
+ names = [hook for hook, infos in pre_result.items()
+ if any(result["state"] == "succeed" for result in infos.values())]
+ # FIXME : what do in case of partial success/failure ...
if not names:
- ret_failed = {n: [p for p, c in v.items() if c['state'] == "failed"] for n, v in pre_result.items()}
+ ret_failed = [hook for hook, infos in pre_result.items()
+ if any(result["state"] == "failed" for result in infos.values())]
raise YunohostError('service_regenconf_failed',
services=', '.join(ret_failed))
From 16245f53d9591fcfeca70e5c54604ba3d26c2185 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 4 Mar 2019 18:33:09 +0100
Subject: [PATCH 096/199] Fix listing of succeed/failed for backup and restore
---
src/yunohost/backup.py | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py
index d33f75e3a..872896ecb 100644
--- a/src/yunohost/backup.py
+++ b/src/yunohost/backup.py
@@ -593,10 +593,14 @@ class BackupManager():
env=env_dict,
chdir=self.work_dir)
- ret_succeed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "succeed"] for n, v in ret.items()}.items() if val}
- ret_failed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "failed"] for n, v in ret.items()}.items() if val}
+ ret_succeed = {hook: {path:result["state"] for path, result in infos.items()}
+ for hook, infos in ret.items()
+ if any(result["state"] == "succeed" for result in infos.values())}
+ ret_failed = {hook: {path:result["state"] for path, result in infos.items.items()}
+ for hook, infos in ret.items()
+ if any(result["state"] == "failed" for result in infos.values())}
- if ret_succeed != []:
+ if ret_succeed.keys() != []:
self.system_return = ret_succeed
# Add files from targets (which they put in the CSV) to the list of
@@ -1180,14 +1184,16 @@ class RestoreManager():
env=env_dict,
chdir=self.work_dir)
- ret_succeed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "succeed"] for n, v in ret.items()}.items() if val}
- ret_failed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "failed"] for n, v in ret.items()}.items() if val}
+ ret_succeed = [hook for hook, infos in ret.items()
+ if any(result["state"] == "succeed" for result in infos.values())]
+ ret_failed = [hook for hook, infos in ret.items()
+ if any(result["state"] == "failed" for result in infos.values())]
- for part in ret_succeed.keys():
+ for part in ret_succeed:
self.targets.set_result("system", part, "Success")
error_part = []
- for part in ret_failed.keys():
+ for part in ret_failed:
logger.error(m18n.n('restore_system_part_failed', part=part))
self.targets.set_result("system", part, "Error")
error_part.append(part)
From 88b7d77610d6493d62a490fa3ff758a992e7e270 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 4 Mar 2019 18:58:04 +0100
Subject: [PATCH 097/199] Display raw json content in case of exception
---
locales/en.json | 2 +-
src/yunohost/hook.py | 16 +++++++++-------
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/locales/en.json b/locales/en.json
index a6d95ada1..ca1d9c8a1 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -211,7 +211,7 @@
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
"hook_exec_failed": "Script execution failed: {path:s}",
"hook_exec_not_terminated": "Script execution hasn\u2019t terminated: {path:s}",
- "hook_json_return_error": "Failed to read return from hook {path:s}. Error: {msg:s}",
+ "hook_json_return_error": "Failed to read return from hook {path:s}. Error: {msg:s}. Raw content: {raw_content}",
"hook_list_by_invalid": "Invalid property to list hook by",
"hook_name_unknown": "Unknown hook name '{name:s}'",
"installation_complete": "Installation complete",
diff --git a/src/yunohost/hook.py b/src/yunohost/hook.py
index 961caf606..c4605b6e8 100644
--- a/src/yunohost/hook.py
+++ b/src/yunohost/hook.py
@@ -395,15 +395,17 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
elif raise_on_error and returncode != 0:
raise YunohostError('hook_exec_failed', path=path)
+ raw_content = None
try:
-
- with open(stdreturn, 'r') as f:
- if f.read() != '':
- returnjson = read_json(stdreturn)
- else:
- returnjson = {}
+ with open(stdreturn, 'r') as f:
+ raw_content = f.read()
+ if raw_content != '':
+ returnjson = read_json(stdreturn)
+ else:
+ returnjson = {}
except Exception as e:
- raise YunohostError('hook_json_return_error', path=path, msg=str(e))
+ raise YunohostError('hook_json_return_error', path=path, msg=str(e),
+ raw_content=raw_content)
finally:
stdreturndir = os.path.split(stdreturn)[0]
os.remove(stdreturn)
From 5516e96d076eba0fc98f714b73e365693ddfc7a2 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 4 Mar 2019 19:05:43 +0100
Subject: [PATCH 098/199] Simpler fetching of failed/succeeded hooks in
CustomBackupMethod
---
src/yunohost/backup.py | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py
index 872896ecb..867de3ea9 100644
--- a/src/yunohost/backup.py
+++ b/src/yunohost/backup.py
@@ -1941,7 +1941,8 @@ class CustomBackupMethod(BackupMethod):
ret = hook_callback('backup_method', [self.method],
args=self._get_args('need_mount'))
- ret_succeed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "succeed"] for n, v in ret.items()}.items() if val}
+ ret_succeed = [hook for hook, infos in ret.items()
+ if any(result["state"] == "succeed" for result in infos.values())]
self._need_mount = True if ret_succeed else False
return self._need_mount
@@ -1955,7 +1956,9 @@ class CustomBackupMethod(BackupMethod):
ret = hook_callback('backup_method', [self.method],
args=self._get_args('backup'))
- ret_failed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "failed"] for n, v in ret.items()}.items() if val}
+
+ ret_failed = [hook for hook, infos in ret.items()
+ if any(result["state"] == "failed" for result in infos.values())]
if ret_failed:
raise YunohostError('backup_custom_backup_error')
@@ -1969,7 +1972,9 @@ class CustomBackupMethod(BackupMethod):
super(CustomBackupMethod, self).mount(restore_manager)
ret = hook_callback('backup_method', [self.method],
args=self._get_args('mount'))
- ret_failed = {k: val for k, val in {n: [p for p, c in v.items() if c['state'] == "failed"] for n, v in ret.items()}.items() if val}
+
+ ret_failed = [hook for hook, infos in ret.items()
+ if any(result["state"] == "failed" for result in infos.values())]
if ret_failed:
raise YunohostError('backup_custom_mount_error')
From e3dfd63481fd72109ff2bf8bac562b123b95ad90 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 4 Mar 2019 22:54:02 +0100
Subject: [PATCH 099/199] Replace hard-corded value with constant defined above
---
data/helpers.d/psql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index 324cfee83..705aeeb9a 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -244,7 +244,7 @@ ynh_psql_remove_db() {
#
# usage: ynh_psql_test_if_first_run
ynh_psql_test_if_first_run() {
- if [ -f /etc/yunohost/psql ]; then
+ if [ -f "$PSQL_ROOT_PWD_FILE" ]; then
echo "PostgreSQL is already installed, no need to create master password"
else
local pgsql="$(ynh_string_random)"
From def005d2da29763fc7d45d3398e0f82a896641d6 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 5 Mar 2019 00:42:20 +0100
Subject: [PATCH 100/199] Fix weird message
---
locales/en.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/locales/en.json b/locales/en.json
index 1157e0a54..f7a65a883 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -218,7 +218,7 @@
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
"hook_exec_failed": "Script execution failed: {path:s}",
- "hook_exec_not_terminated": "Script execution hasn\u2019t terminated: {path:s}",
+ "hook_exec_not_terminated": "Script execution did not finish properly: {path:s}",
"hook_list_by_invalid": "Invalid property to list hook by",
"hook_name_unknown": "Unknown hook name '{name:s}'",
"installation_complete": "Installation complete",
From f1e097a5bdb4bbc462fa823a42cb21e5e9fd7d1a Mon Sep 17 00:00:00 2001
From: Kayou
Date: Thu, 7 Mar 2019 11:25:32 +0100
Subject: [PATCH 101/199] Fix tab
---
data/helpers.d/psql | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index 705aeeb9a..f0be628ea 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -74,9 +74,9 @@ ynh_psql_create_db() {
local db=$1
local user=${2:-}
- local sql="CREATE DATABASE ${db};"
+ local sql="CREATE DATABASE ${db};"
- # grant all privilegies to user
+ # grant all privilegies to user
if [ -n "$user" ]; then
sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;"
fi
From 5e0f63eab488ef6430bfa6bd92f050baf93cc175 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Thu, 7 Mar 2019 15:45:48 +0100
Subject: [PATCH 102/199] Reject app password if they contains { or }
---
locales/en.json | 1 +
src/yunohost/app.py | 3 +++
2 files changed, 4 insertions(+)
diff --git a/locales/en.json b/locales/en.json
index f7a65a883..a70da7b82 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -380,6 +380,7 @@
"pattern_port_or_range": "Must be a valid port number (i.e. 0-65535) or range of ports (e.g. 100:200)",
"pattern_positive_number": "Must be a positive number",
"pattern_username": "Must be lower-case alphanumeric and underscore characters only",
+ "pattern_password_app": "Sorry, passwords should not contain the following characters: {forbidden_chars}",
"port_already_closed": "Port {port:d} is already closed for {ip_version:s} connections",
"port_already_opened": "Port {port:d} is already opened for {ip_version:s} connections",
"port_available": "Port {port:d} is available",
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index be0bb5a55..fa05ebe47 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -2287,6 +2287,9 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
else:
raise YunohostError('app_argument_choice_invalid', name=arg_name, choices='yes, no, y, n, 1, 0')
elif arg_type == 'password':
+ forbidden_chars = "{}"
+ if any(char in arg_value for char in forbidden_chars):
+ raise YunohostError('pattern_password_app', forbidden_chars=forbidden_chars)
from yunohost.utils.password import assert_password_is_strong_enough
assert_password_is_strong_enough('user', arg_value)
args_dict[arg_name] = arg_value
From 55e9df75d0dd97bbf1eece1e0a39bbc645d49df2 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Thu, 7 Mar 2019 17:03:59 +0100
Subject: [PATCH 103/199] Clean tmp directory if it not empty
---
src/yunohost/backup.py | 64 +++++++++++++++++++++++++-----------------
1 file changed, 38 insertions(+), 26 deletions(-)
diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py
index f9505fb66..98758a57a 100644
--- a/src/yunohost/backup.py
+++ b/src/yunohost/backup.py
@@ -326,10 +326,19 @@ class BackupManager():
if not os.path.isdir(self.work_dir):
filesystem.mkdir(self.work_dir, 0o750, parents=True, uid='admin')
elif self.is_tmp_work_dir:
- logger.debug("temporary directory for backup '%s' already exists",
+
+ logger.debug("temporary directory for backup '%s' already exists... attempting to clean it",
self.work_dir)
- # FIXME May be we should clean the workdir here
- raise YunohostError('backup_output_directory_not_empty')
+
+ # Try to recursively unmount stuff (from a previously failed backup ?)
+ if _recursive_umount(self.work_dir) > 0:
+ raise YunohostError('backup_output_directory_not_empty')
+ else:
+ # If umount succeeded, remove the directory (we checked that
+ # we're in /home/yunohost.backup/tmp so that should be okay...
+ # c.f. method clean() which also does this)
+ filesystem.rm(self.work_dir, True, True)
+ filesystem.mkdir(self.work_dir, 0o750, parents=True, uid='admin')
#
# Backup target management #
@@ -1514,34 +1523,12 @@ class BackupMethod(object):
directories of the working directories
"""
if self.need_mount():
- if self._recursive_umount(self.work_dir) > 0:
+ if _recursive_umount(self.work_dir) > 0:
raise YunohostError('backup_cleaning_failed')
if self.manager.is_tmp_work_dir:
filesystem.rm(self.work_dir, True, True)
- def _recursive_umount(self, directory):
- """
- Recursively umount sub directories of a directory
-
- Args:
- directory -- a directory path
- """
- mount_lines = subprocess.check_output("mount").split("\n")
-
- points_to_umount = [line.split(" ")[2]
- for line in mount_lines
- if len(line) >= 3 and line.split(" ")[2].startswith(directory)]
- ret = 0
- for point in reversed(points_to_umount):
- ret = subprocess.call(["umount", point])
- if ret != 0:
- ret = 1
- logger.warning(m18n.n('backup_cleaning_failed', point))
- continue
-
- return ret
-
def _check_is_enough_free_space(self):
"""
Check free space in repository or output directory before to backup
@@ -2011,6 +1998,7 @@ def backup_create(name=None, description=None, methods=[],
# Check that output directory is empty
if os.path.isdir(output_directory) and no_compress and \
os.listdir(output_directory):
+
raise YunohostError('backup_output_directory_not_empty')
elif no_compress:
raise YunohostError('backup_output_directory_required')
@@ -2315,6 +2303,30 @@ def _call_for_each_path(self, callback, csv_path=None):
callback(self, row['source'], row['dest'])
+def _recursive_umount(directory):
+ """
+ Recursively umount sub directories of a directory
+
+ Args:
+ directory -- a directory path
+ """
+ mount_lines = subprocess.check_output("mount").split("\n")
+
+ points_to_umount = [line.split(" ")[2]
+ for line in mount_lines
+ if len(line) >= 3 and line.split(" ")[2].startswith(directory)]
+
+ ret = 0
+ for point in reversed(points_to_umount):
+ ret = subprocess.call(["umount", point])
+ if ret != 0:
+ ret = 1
+ logger.warning(m18n.n('backup_cleaning_failed', point))
+ continue
+
+ return ret
+
+
def free_space_in_directory(dirpath):
stat = os.statvfs(dirpath)
return stat.f_frsize * stat.f_bavail
From 135ac60d94d81e35ce790d0c0e7d7d037a490e03 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Thu, 7 Mar 2019 17:04:40 +0100
Subject: [PATCH 104/199] Clarify arguments usage
---
src/yunohost/backup.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py
index 98758a57a..5608c7478 100644
--- a/src/yunohost/backup.py
+++ b/src/yunohost/backup.py
@@ -337,7 +337,7 @@ class BackupManager():
# If umount succeeded, remove the directory (we checked that
# we're in /home/yunohost.backup/tmp so that should be okay...
# c.f. method clean() which also does this)
- filesystem.rm(self.work_dir, True, True)
+ filesystem.rm(self.work_dir, recursive=True, force=True)
filesystem.mkdir(self.work_dir, 0o750, parents=True, uid='admin')
#
@@ -913,7 +913,7 @@ class RestoreManager():
ret = subprocess.call(["umount", self.work_dir])
if ret != 0:
logger.warning(m18n.n('restore_cleaning_failed'))
- filesystem.rm(self.work_dir, True, True)
+ filesystem.rm(self.work_dir, recursive=True, force=True)
#
# Restore target manangement #
From 7f779ddd1cf60ba808f5ca0569c121be5fb75e62 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Thu, 7 Mar 2019 17:10:01 +0100
Subject: [PATCH 105/199] This ambiguity about 'ret' definitely looks like a
bug ...
---
src/yunohost/backup.py | 10 +++++-----
src/yunohost/tests/test_backuprestore.py | 2 +-
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py
index 5608c7478..039944264 100644
--- a/src/yunohost/backup.py
+++ b/src/yunohost/backup.py
@@ -331,7 +331,7 @@ class BackupManager():
self.work_dir)
# Try to recursively unmount stuff (from a previously failed backup ?)
- if _recursive_umount(self.work_dir) > 0:
+ if not _recursive_umount(self.work_dir):
raise YunohostError('backup_output_directory_not_empty')
else:
# If umount succeeded, remove the directory (we checked that
@@ -1523,7 +1523,7 @@ class BackupMethod(object):
directories of the working directories
"""
if self.need_mount():
- if _recursive_umount(self.work_dir) > 0:
+ if not _recursive_umount(self.work_dir):
raise YunohostError('backup_cleaning_failed')
if self.manager.is_tmp_work_dir:
@@ -2316,15 +2316,15 @@ def _recursive_umount(directory):
for line in mount_lines
if len(line) >= 3 and line.split(" ")[2].startswith(directory)]
- ret = 0
+ everything_went_fine = True
for point in reversed(points_to_umount):
ret = subprocess.call(["umount", point])
if ret != 0:
- ret = 1
+ everything_went_fine = False
logger.warning(m18n.n('backup_cleaning_failed', point))
continue
- return ret
+ return everything_went_fine
def free_space_in_directory(dirpath):
diff --git a/src/yunohost/tests/test_backuprestore.py b/src/yunohost/tests/test_backuprestore.py
index 14c479d9a..73728240f 100644
--- a/src/yunohost/tests/test_backuprestore.py
+++ b/src/yunohost/tests/test_backuprestore.py
@@ -571,7 +571,7 @@ def test_backup_binds_are_readonly(monkeypatch):
assert "Read-only file system" in output
- if self._recursive_umount(self.work_dir) > 0:
+ if not _recursive_umount(self.work_dir):
raise Exception("Backup cleaning failed !")
self.clean()
From a974d08897741e577353644acd28cad6c4727685 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 8 Mar 2019 01:22:32 +0100
Subject: [PATCH 106/199] Fix use case of app_fetchlist with url=None
---
src/yunohost/app.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index de759f04f..99d3784bc 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -97,7 +97,7 @@ def app_fetchlist(url=None, name=None):
name -- Name of the list
url -- URL of remote JSON list
"""
- if not url.endswith(".json"):
+ if url and not url.endswith(".json"):
raise YunohostError("This is not a valid application list url. It should end with .json.")
# If needed, create folder where actual appslists are stored
From ea98cf557ef3c93fdb3f47304a5745d38418a894 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 8 Mar 2019 19:53:56 +0100
Subject: [PATCH 107/199] Avoid miserably failing when attempting to create
link in some edge case
---
src/yunohost/backup.py | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py
index 53919f2cc..80e13c273 100644
--- a/src/yunohost/backup.py
+++ b/src/yunohost/backup.py
@@ -1633,9 +1633,18 @@ class BackupMethod(object):
# 'NUMBER OF HARD LINKS > 1' see #1043
cron_path = os.path.abspath('/etc/cron') + '.'
if not os.path.abspath(src).startswith(cron_path):
- os.link(src, dest)
- # Success, go to next file to organize
- continue
+ try:
+ os.link(src, dest)
+ except Exception as e:
+ # This kind of situation may happen when src and dest are on different
+ # logical volume ... even though the st_dev check previously match...
+ # E.g. this happens when running an encrypted hard drive
+ # where everything is mapped to /dev/mapper/some-stuff
+ # yet there are different devices behind it or idk ...
+ logger.warning("Could not link %s to %s (%s) ... falling back to regular copy." % (src, dest, str(e)))
+ else:
+ # Success, go to next file to organize
+ continue
# If mountbind or hardlink couldnt be created,
# prepare a list of files that need to be copied
From bf659db300bbe658bbe180c3a3deb306f8c0f6e9 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 8 Mar 2019 19:54:26 +0100
Subject: [PATCH 108/199] Not sure why this stop working, maybe new pytest
version or something...
---
src/yunohost/tests/test_backuprestore.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/tests/test_backuprestore.py b/src/yunohost/tests/test_backuprestore.py
index 14c479d9a..54f31bcb2 100644
--- a/src/yunohost/tests/test_backuprestore.py
+++ b/src/yunohost/tests/test_backuprestore.py
@@ -42,7 +42,7 @@ def setup_function(function):
assert len(backup_list()["archives"]) == 0
- markers = function.__dict__.keys()
+ markers = [m.name for m in function.__dict__.get("pytestmark",[])]
if "with_wordpress_archive_from_2p4" in markers:
add_archive_wordpress_from_2p4()
@@ -82,7 +82,7 @@ def teardown_function(function):
delete_all_backups()
uninstall_test_apps_if_needed()
- markers = function.__dict__.keys()
+ markers = [m.name for m in function.__dict__.get("pytestmark",[])]
if "clean_opt_dir" in markers:
shutil.rmtree("/opt/test_backup_output_directory")
From ea8605db5ccab33c7ce64cb7ec92a4283471b46a Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Fri, 8 Mar 2019 23:32:23 +0100
Subject: [PATCH 109/199] [enh] Support php versions in ynh_add_fpm_config
---
data/helpers.d/backend | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/data/helpers.d/backend b/data/helpers.d/backend
index 1532601a8..fbebf278a 100644
--- a/data/helpers.d/backend
+++ b/data/helpers.d/backend
@@ -240,11 +240,21 @@ ynh_remove_nginx_config () {
# Create a dedicated php-fpm config
#
-# usage: ynh_add_fpm_config
+# usage: ynh_add_fpm_config [--phpversion=7.X]
+# | arg: -v, --phpversion - Version of php to use.
ynh_add_fpm_config () {
+ # Declare an array to define the options of this helper.
+ local legacy_args=v
+ declare -Ar args_array=( [v]=phpversion= )
+ local phpversion
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+
# Configure PHP-FPM 7.0 by default
- local fpm_config_dir="/etc/php/7.0/fpm"
- local fpm_service="php7.0-fpm"
+ phpversion="${phpversion:-7.0}"
+
+ local fpm_config_dir="/etc/php/$phpversion/fpm"
+ local fpm_service="php${phpversion}-fpm"
# Configure PHP-FPM 5 on Debian Jessie
if [ "$(ynh_get_debian_release)" == "jessie" ]; then
fpm_config_dir="/etc/php5/fpm"
@@ -258,6 +268,7 @@ ynh_add_fpm_config () {
ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf"
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf"
ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$finalphpconf"
+ ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf"
sudo chown root: "$finalphpconf"
ynh_store_file_checksum --file="$finalphpconf"
From 2818abe5000e2a8d08624bf459c908f2c3b76696 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Sat, 9 Mar 2019 16:45:53 +0100
Subject: [PATCH 110/199] Update global.conf
---
data/templates/nginx/plain/global.conf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/templates/nginx/plain/global.conf b/data/templates/nginx/plain/global.conf
index ca8721afb..07f7c49ea 100644
--- a/data/templates/nginx/plain/global.conf
+++ b/data/templates/nginx/plain/global.conf
@@ -1,2 +1,2 @@
server_tokens off;
-gzip_types text/css text/javascript application/javascript;
+gzip off;
From 945912cc983c9b2fe67cf9a6905f0a07d37d2c4c Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Sun, 10 Mar 2019 13:22:07 +0100
Subject: [PATCH 111/199] [fix] ynh_app_setting_get and ynh_app_setting_delete
don't have a fourth argument.
---
data/helpers.d/setting | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/setting b/data/helpers.d/setting
index fb833281a..7aae6be7b 100644
--- a/data/helpers.d/setting
+++ b/data/helpers.d/setting
@@ -60,7 +60,7 @@ ynh_app_setting_delete() {
#
ynh_app_setting()
{
- ACTION="$1" APP="$2" KEY="$3" VALUE="$4" python - <
Date: Sun, 10 Mar 2019 23:57:37 +0100
Subject: [PATCH 112/199] [microdecision] c.f. 25efab7 .. there's no way to
include files in sshd_config
---
.../0007_ssh_conf_managed_by_yunohost_step1.py | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
index 080cc0163..d188ff024 100644
--- a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
+++ b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
@@ -49,10 +49,6 @@ class MyMigration(Migration):
if dsa:
settings_set("service.ssh.allow_deprecated_dsa_hostkey", True)
- # Create sshd_config.d dir
- if not os.path.exists(SSHD_CONF + '.d'):
- mkdir(SSHD_CONF + '.d', 0o755, uid='root', gid='root')
-
# Here, we make it so that /etc/ssh/sshd_config is managed
# by the regen conf (in particular in the case where the
# from_script flag is present - in which case it was *not*
From 1d37dd4fa28a7529dd438f1aaa544d2551894b0e Mon Sep 17 00:00:00 2001
From: "ljf (zamentur)"
Date: Wed, 13 Mar 2019 13:32:50 +0100
Subject: [PATCH 113/199] [fix] Missing import
---
src/yunohost/tests/test_backuprestore.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/yunohost/tests/test_backuprestore.py b/src/yunohost/tests/test_backuprestore.py
index 73728240f..893925e83 100644
--- a/src/yunohost/tests/test_backuprestore.py
+++ b/src/yunohost/tests/test_backuprestore.py
@@ -10,7 +10,7 @@ from moulinette import m18n
from moulinette.core import init_authenticator
from yunohost.app import app_install, app_remove, app_ssowatconf
from yunohost.app import _is_installed
-from yunohost.backup import backup_create, backup_restore, backup_list, backup_info, backup_delete
+from yunohost.backup import backup_create, backup_restore, backup_list, backup_info, backup_delete, _recursive_umount
from yunohost.domain import _get_maindomain
from yunohost.utils.error import YunohostError
From 73aefc6bc8aaf3f01e983300afad1124d7b9eecd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9?=
Date: Tue, 5 Feb 2019 20:09:15 +0000
Subject: [PATCH 114/199] Translated using Weblate (Russian)
Currently translated at 9.4% (44 of 465 strings)
---
locales/ru.json | 38 +++++++++++++++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/locales/ru.json b/locales/ru.json
index 2658446bc..306a8763a 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -6,5 +6,41 @@
"app_already_installed": "{app:s} уже установлено",
"app_already_installed_cant_change_url": "Это приложение уже установлено. URL не может быть изменен только с помощью этой функции. Изучите `app changeurl`, если это доступно.",
"app_argument_choice_invalid": "Неверный выбор для аргумента '{name:s}', Это должно быть '{choices:s}'",
- "app_argument_invalid": "Недопустимое значение аргумента '{name:s}': {error:s}'"
+ "app_argument_invalid": "Недопустимое значение аргумента '{name:s}': {error:s}'",
+ "app_already_up_to_date": "{app:s} уже обновлено",
+ "app_argument_required": "Аргумент '{name:s}' необходим",
+ "app_change_no_change_url_script": "Приложение {app_name:s} не поддерживает изменение URL, вы должны обновить его.",
+ "app_change_url_identical_domains": "Старый и новый domain/url_path идентичны ('{domain:s}{path:s}'), ничего делать не надо.",
+ "app_change_url_no_script": "Приложение '{app_name:s}' не поддерживает изменение url. Наверное, вам нужно обновить приложение.",
+ "app_change_url_success": "Успешно изменён {app:s} url на {domain:s}{path:s}",
+ "app_extraction_failed": "Невозможно извлечь файлы для инсталляции",
+ "app_id_invalid": "Неправильный id приложения",
+ "app_incompatible": "Приложение {app} несовместимо с вашей версией YonoHost",
+ "app_install_files_invalid": "Неправильные файлы инсталляции",
+ "app_location_already_used": "Приложение '{app}' уже установлено по этому адресу ({path})",
+ "app_location_install_failed": "Невозможно установить приложение в это место, потому что оно конфликтует с приложением, '{other_app}' установленном на '{other_path}'",
+ "app_location_unavailable": "Этот url отсутствует или конфликтует с уже установленным приложением или приложениями: {apps:s}",
+ "app_manifest_invalid": "Недопустимый манифест приложения: {error}",
+ "app_no_upgrade": "Нет приложений, требующих обновления",
+ "app_not_correctly_installed": "{app:s} , кажется, установлены неправильно",
+ "app_not_installed": "{app:s} не установлены",
+ "app_not_properly_removed": "{app:s} удалены неправильно",
+ "app_package_need_update": "Пакет приложения {app} должен быть обновлён в соответствии с изменениями YonoHost",
+ "app_removed": "{app:s} удалено",
+ "app_requirements_checking": "Проверяю необходимые пакеты для {app}...",
+ "app_sources_fetch_failed": "Невозможно получить исходные файлы",
+ "app_unknown": "Неизвестное приложение",
+ "app_upgrade_app_name": "Обновление приложения {app}...",
+ "app_upgrade_failed": "Невозможно обновить {app:s}",
+ "app_upgrade_some_app_failed": "Невозможно обновить некоторые приложения",
+ "app_upgraded": "{app:s} обновлено",
+ "appslist_corrupted_json": "Не могу загрузить список приложений. Кажется, {filename:s} поврежден.",
+ "appslist_fetched": "Был выбран список приложений {appslist:s}",
+ "appslist_name_already_tracked": "Уже есть зарегистрированный список приложений по имени {name:s}.",
+ "appslist_removed": "Список приложений {appslist:s} удалён",
+ "appslist_retrieve_bad_format": "Неверный файл списка приложений{appslist:s}",
+ "appslist_retrieve_error": "Невозможно получить список удаленных приложений {appslist:s}: {error:s}",
+ "appslist_unknown": "Список приложений {appslist:s} неизвестен.",
+ "appslist_url_already_tracked": "Это уже зарегистрированный список приложений с url{url:s}.",
+ "installation_complete": "Установка завершена"
}
From 4ed63926804086fff2a037fb522796b0dcb145e4 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 13 Mar 2019 16:26:18 +0100
Subject: [PATCH 115/199] Update changelog for 3.5.0 testing
---
debian/changelog | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index 7be4212fe..f8485e020 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,54 @@
+yunohost (3.5.0) testing; urgency=low
+
+ Core
+ ----
+
+ - [fix] Disable gzip entirely to avoid BREACH attacks (#675)
+ - [fix] Backup tests were broken (#673)
+ - [fix] Backup fails because output directory not empty (#672)
+ - [fix] Reject app password if they contains { or } (#671)
+ - [enh] Allow `display_text` 'fake' argument in manifest.json (#669)
+ - [fix] Optimize dyndns requests (#662)
+ - [enh] Don't add Strict-Transport-Security header in nginx conf if using a selfsigned cert (#661)
+ - [enh] Add apt-transport-https to dependencies (#658)
+ - [enh] Cache results from meltdown vulnerability checker (#656)
+ - [enh] Ensure the tar file is closed during the backup (#655)
+ - [enh] Be able to define hook to trigger when changing a setting (#654)
+ - [enh] Assert dpkg is not broken before app install (#652)
+ - [fix] Loading only one helper file leads to errors because missing getopts (#651)
+ - [enh] Improve / add some messages to improve UX (#650)
+ - [enh] Reload fail2ban instead of restart (#649)
+ - [enh] Add IPv6 resolvers from diyisp.org to resolv.dnsmasq.conf (#639)
+ - [fix] Remove old SMTP port (465) from fail2ban jail.conf (#637)
+ - [enh] Improve protection against indexation from the robots. (#622)
+ - [enh] Allow hooks to return data (#526)
+ - [fix] Do not make version number available from web API to unauthenticated users (#291)
+ - [i18n] Improve Russian and Chinese (Mandarin) translations
+
+ App helpers
+ -----------
+
+ - [enh] Optimize app setting helpers (#663, #676)
+ - [enh] Handle `ynh_install_nodejs` for arm64 / aarch64 (#660)
+ - [enh] Update postgresql helpers (#657)
+ - [enh] Print diff of files when backup by `ynh_backup_if_checksum_is_different` (#648)
+ - [enh] Add app debugger helper (#647)
+ - [fix] Escape double quote before eval in getopts (#646)
+ - [fix] `ynh_local_curl` not using the right url in some cases (#644)
+ - [fix] Get rid of annoying 'unable to initialize frontend' messages (#643)
+ - [enh] Check if dpkg is not broken when calling `ynh_wait_dpkg_free` (#638)
+ - [enh] Warn the packager that `ynh_secure_remove` should be used with only one arg… (#635, #642)
+ - [enh] Add `ynh_script_progression` helper (#634)
+ - [enh] Add `ynh_systemd_action` helper (#633)
+ - [enh] Allow to dig deeper into an archive with `ynh_setup_source` (#630)
+ - [enh] Use getops (#561)
+ - [enh] Add `ynh_check_app_version_changed` helper (#521)
+ - [enh] Add fail2ban helpers (#364)
+
+ Contributors: Alexandre Aubin, Jimmy Monin, Josué Tille, Kayou, Laurent Peuch, Lukas Fülling, Maniack Crudelis, Taekiro, frju365, ljf, opi, yalh76, Алексей
+
+ -- Alexandre Aubin Wed, 13 Mar 2019 16:10:00 +0000
+
yunohost (3.4.2.4) stable; urgency=low
- [fix] Meltdown vulnerability checker something outputing trash instead of pure json
From 485cb4b5c75a7a74ab95104ffdc6eb4c7b00bfeb Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Wed, 13 Mar 2019 18:42:07 +0100
Subject: [PATCH 116/199] [fix] Delete properly group as well as user
---
data/helpers.d/user | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/user b/data/helpers.d/user
index d716bf03b..b28ee490a 100644
--- a/data/helpers.d/user
+++ b/data/helpers.d/user
@@ -63,6 +63,21 @@ ynh_system_user_exists() {
getent passwd "$username" &>/dev/null
}
+# Check if a group exists on the system
+#
+# usage: ynh_system_group_exists --group=group
+# | arg: -g, --group - the group to check
+ynh_system_group_exists() {
+ # Declare an array to define the options of this helper.
+ local legacy_args=g
+ declare -Ar args_array=( [g]=group= )
+ local group
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+
+ getent group "$group" &>/dev/null
+}
+
# Create a system user
#
# examples:
@@ -116,11 +131,21 @@ ynh_system_user_delete () {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
- if ynh_system_user_exists "$username" # Check if the user exists on the system
+ # Check if the user exists on the system
+ if ynh_system_user_exists "$username"
then
echo "Remove the user $username" >&2
- sudo userdel $username
+ deluser $username
else
echo "The user $username was not found" >&2
fi
+
+ # Check if the group exists on the system
+ if ynh_system_group_exists "$username"
+ then
+ echo "Remove the group $username" >&2
+ delgroup $username
+ else
+ echo "The group $username was not found" >&2
+ fi
}
From ab574bb218a414f975651ac5b386bed9d9317363 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Wed, 13 Mar 2019 18:57:27 +0100
Subject: [PATCH 117/199] [enh] reload-or-restart instead of reload
---
data/helpers.d/system | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index bfc20cb33..fd552db7f 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -59,7 +59,7 @@ ynh_get_debian_release () {
# Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started
#
# usage: ynh_systemd_action [-n service_name] [-a action] [ [-l "line to match"] [-p log_path] [-t timeout] [-e length] ]
-# | arg: -n, --service_name= - Name of the service to reload. Default : $app
+# | arg: -n, --service_name= - Name of the service to start. Default : $app
# | arg: -a, --action= - Action to perform with systemctl. Default: start
# | arg: -l, --line_match= - Line to match - The line to find in the log to attest the service have finished to boot.
# If not defined it don't wait until the service is completely started.
@@ -107,6 +107,12 @@ ynh_systemd_action() {
fi
ynh_print_info --message="${action^} the service $service_name"
+
+ # Use reload-or-restart instead of reload. So it wouldn't fail if the service isn't running.
+ if [ "$action" == "reload" ]; then
+ action="reload-or-restart"
+ fi
+
systemctl $action $service_name \
|| ( journalctl --no-pager --lines=$length -u $service_name >&2 \
; test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2 \
From a8f88e7232ca39005e9d78e45481ee8bb1e6e771 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 13 Mar 2019 19:11:49 +0100
Subject: [PATCH 118/199] [yolo] gzip off in global.conf breaks everything
because conflict with gzip on; in nginx.conf ... Moving it to server blocs
---
data/templates/nginx/plain/global.conf | 1 -
data/templates/nginx/plain/yunohost_admin.conf | 4 ++++
data/templates/nginx/server.tpl.conf | 4 ++++
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/data/templates/nginx/plain/global.conf b/data/templates/nginx/plain/global.conf
index 07f7c49ea..b3a5f356a 100644
--- a/data/templates/nginx/plain/global.conf
+++ b/data/templates/nginx/plain/global.conf
@@ -1,2 +1 @@
server_tokens off;
-gzip off;
diff --git a/data/templates/nginx/plain/yunohost_admin.conf b/data/templates/nginx/plain/yunohost_admin.conf
index 2493e4033..ff61b8638 100644
--- a/data/templates/nginx/plain/yunohost_admin.conf
+++ b/data/templates/nginx/plain/yunohost_admin.conf
@@ -51,6 +51,10 @@ server {
more_set_headers "X-Permitted-Cross-Domain-Policies : none";
more_set_headers "X-Frame-Options : SAMEORIGIN";
+ # Disable gzip to protect against BREACH
+ # Read https://trac.nginx.org/nginx/ticket/1720 (text/html cannot be disabled!)
+ gzip off;
+
location / {
return 302 https://$http_host/yunohost/admin;
}
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index 43d38ca98..d8793ef05 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -71,6 +71,10 @@ server {
resolver_timeout 5s;
{% endif %}
+ # Disable gzip to protect against BREACH
+ # Read https://trac.nginx.org/nginx/ticket/1720 (text/html cannot be disabled!)
+ gzip off;
+
access_by_lua_file /usr/share/ssowat/access.lua;
include /etc/nginx/conf.d/{{ domain }}.d/*.conf;
From e3d8929dec650d6980e64a3b17f000150ac27c6e Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 13 Mar 2019 19:24:00 +0100
Subject: [PATCH 119/199] Update changelog for 3.5.0.1
---
debian/changelog | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index f8485e020..7290e935d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+yunohost (3.5.0.1) testing; urgency=low
+
+ - [fix] #675 introduced a bug in nginx conf ...
+
+ -- Alexandre Aubin Wed, 13 Mar 2019 19:23:00 +0000
+
yunohost (3.5.0) testing; urgency=low
Core
From 1507e11e6eb84551e4e44ce4daf5241d536e22dd Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Wed, 13 Mar 2019 19:32:10 +0100
Subject: [PATCH 120/199] Do not warn if group isn't exist
---
data/helpers.d/user | 2 --
1 file changed, 2 deletions(-)
diff --git a/data/helpers.d/user b/data/helpers.d/user
index b28ee490a..5a65f7642 100644
--- a/data/helpers.d/user
+++ b/data/helpers.d/user
@@ -145,7 +145,5 @@ ynh_system_user_delete () {
then
echo "Remove the group $username" >&2
delgroup $username
- else
- echo "The group $username was not found" >&2
fi
}
From e24890c2f2f01bd6f3a934bf30ee713ad6503564 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Thu, 14 Mar 2019 03:48:35 +0100
Subject: [PATCH 121/199] Update changelog for 3.5.0.2
---
debian/changelog | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index 7290e935d..444d797e1 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+yunohost (3.5.0.2) testing; urgency=low
+
+ - [fix] Make sure that `ynh_system_user_delete` also deletes the group (#680)
+ - [enh] `ynh_systemd_action` : reload-or-restart instead of just reload (#681)
+
+ Last minute fixes by Maniack ;)
+
+ -- Alexandre Aubin Thu, 14 Mar 2019 03:45:00 +0000
+
yunohost (3.5.0.1) testing; urgency=low
- [fix] #675 introduced a bug in nginx conf ...
From 23d7a0005d6f7c17825473b50bd04bf89181aaa1 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Sat, 16 Mar 2019 16:05:32 +0100
Subject: [PATCH 122/199] Escape $ in getopts
---
data/helpers.d/getopts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts
index 7055325f1..891fdaaeb 100644
--- a/data/helpers.d/getopts
+++ b/data/helpers.d/getopts
@@ -152,6 +152,8 @@ ynh_handle_getopts_args () {
fi
# Escape double quote to prevent any interpretation during the eval
all_args[$i]="${all_args[$i]//\"/\\\"}"
+ # Escape $ as well to prevent the string following it to be seen as a variable.
+ all_args[$i]="${all_args[$i]//$/\\\$}"
eval ${option_var}+=\"${all_args[$i]}\"
shift_value=$(( shift_value + 1 ))
@@ -193,6 +195,8 @@ ynh_handle_getopts_args () {
# Escape double quote to prevent any interpretation during the eval
arguments[$i]="${arguments[$i]//\"/\\\"}"
+ # Escape $ as well to prevent the string following it to be seen as a variable.
+ all_args[$i]="${all_args[$i]//$/\\\$}"
# Store each value given as argument in the corresponding variable
# The values will be stored in the same order than $args_array
From ad748a75f62490386c7ca97b92191d3ee2d3fa0d Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Sat, 16 Mar 2019 16:15:54 +0100
Subject: [PATCH 123/199] eval is useful and working before being evil...
---
data/helpers.d/getopts | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts
index 891fdaaeb..90db671c4 100644
--- a/data/helpers.d/getopts
+++ b/data/helpers.d/getopts
@@ -155,6 +155,13 @@ ynh_handle_getopts_args () {
# Escape $ as well to prevent the string following it to be seen as a variable.
all_args[$i]="${all_args[$i]//$/\\\$}"
+ # For the record.
+ # We're using eval here to get the content of the variable stored itself as simple text in $option_var...
+ # Other ways to get that content would be to use either ${!option_var} or declare -g ${option_var}
+ # But... ${!option_var} can't be used as left part of an assignation.
+ # declare -g ${option_var} will create a local variable (despite -g !) and will not be available for the helper itself.
+ # So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one!
+
eval ${option_var}+=\"${all_args[$i]}\"
shift_value=$(( shift_value + 1 ))
fi
From 652edc204cbf9fbcd7fc9d273d429dc05a0eef7f Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Sat, 16 Mar 2019 16:53:07 +0100
Subject: [PATCH 124/199] Syntax fix
---
data/helpers.d/getopts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts
index 90db671c4..70d4a13d3 100644
--- a/data/helpers.d/getopts
+++ b/data/helpers.d/getopts
@@ -203,7 +203,7 @@ ynh_handle_getopts_args () {
# Escape double quote to prevent any interpretation during the eval
arguments[$i]="${arguments[$i]//\"/\\\"}"
# Escape $ as well to prevent the string following it to be seen as a variable.
- all_args[$i]="${all_args[$i]//$/\\\$}"
+ arguments[$i]="${arguments[$i]//$/\\\$}"
# Store each value given as argument in the corresponding variable
# The values will be stored in the same order than $args_array
From 88deea7cec5032536ca23ddaf546bd982e1ce688 Mon Sep 17 00:00:00 2001
From: Weblate
Date: Sat, 16 Mar 2019 21:34:46 +0000
Subject: [PATCH 125/199] Dunno why those changes were not actually commited...
---
locales/ca.json | 61 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 60 insertions(+), 1 deletion(-)
diff --git a/locales/ca.json b/locales/ca.json
index 6c06d55b3..bfad4d2bd 100644
--- a/locales/ca.json
+++ b/locales/ca.json
@@ -21,5 +21,64 @@
"app_location_already_used": "L'aplicació '{app}' ja està instal·lada en aquest camí ({path})",
"app_make_default_location_already_used": "No es pot fer l'aplicació '{app}' per defecte en el domini {domain} ja que ja és utilitzat per una altra aplicació '{other_app}'",
"app_location_install_failed": "No s'ha pogut instal·lar l'aplicació en aquest camí ja que entra en conflicte amb l'aplicació '{other_app}' ja instal·lada a '{other_path}'",
- "app_location_unavailable": "Aquesta url no està disponible o entra en conflicte amb aplicacions ja instal·lades:\n{apps:s}"
+ "app_location_unavailable": "Aquesta url no està disponible o entra en conflicte amb aplicacions ja instal·lades:\n{apps:s}",
+ "app_manifest_invalid": "Manifest d'aplicació incorrecte: {error}",
+ "app_no_upgrade": "No hi ha cap aplicació per actualitzar",
+ "app_not_correctly_installed": "{app:s} sembla estar mal instal·lada",
+ "app_not_installed": "{app:s} no està instal·lada",
+ "app_not_properly_removed": "{app:s} no s'ha pogut suprimir correctament",
+ "app_package_need_update": "El paquet de l'aplicació {app} ha de ser actualitzat per poder seguir els canvis de YunoHost",
+ "app_removed": "{app:s} ha estat suprimida",
+ "app_requirements_checking": "Verificació dels paquets requerits per {app}",
+ "app_requirements_failed": "No es poden satisfer els requeriments per {app}: {error}",
+ "app_requirements_unmeet": "No es compleixen els requeriments per {app}, el paquet {pkgname} ({version}) ha de ser {spec}",
+ "app_sources_fetch_failed": "No s'han pogut carregar els fitxers font",
+ "app_unknown": "Aplicació desconeguda",
+ "app_unsupported_remote_type": "El tipus remot utilitzat per l'aplicació no està suportat",
+ "app_upgrade_app_name": "Actualitzant l'aplicació {app}...",
+ "app_upgrade_failed": "No s'ha pogut actualitzar {app:s}",
+ "app_upgrade_some_app_failed": "No s'han pogut actualitzar algunes aplicacions",
+ "app_upgraded": "{app:s} ha estat actualitzada",
+ "appslist_corrupted_json": "No s'han pogut carregar les llistes d'aplicacions. Sembla que {filename:s} està danyat.",
+ "appslist_could_not_migrate": "No s'ha pogut migrar la llista d'aplicacions {appslist:s}! No s'ha pogut analitzar la URL... L'antic cronjob s'ha guardat a {bkp_file:s}.",
+ "appslist_fetched": "S'ha descarregat la llista d'aplicacions {appslist:s} correctament",
+ "appslist_migrating": "Migrant la llista d'aplicacions {appslist:s} ...",
+ "appslist_name_already_tracked": "Ja hi ha una llista d'aplicacions registrada amb el nom {name:s}.",
+ "appslist_removed": "S'ha eliminat la llista d'aplicacions {appslist:s}",
+ "appslist_retrieve_bad_format": "L'arxiu obtingut per la llista d'aplicacions {appslist:s} no és vàlid",
+ "appslist_retrieve_error": "No s'ha pogut obtenir la llista d'aplicacions remota {appslist:s}: {error:s}",
+ "appslist_unknown": "La llista d'aplicacions {appslist:s} es desconeguda.",
+ "appslist_url_already_tracked": "Ja hi ha una llista d'aplicacions registrada amb al URL {url:s}.",
+ "ask_current_admin_password": "Contrasenya d'administrador actual",
+ "ask_email": "Correu electrònic",
+ "ask_firstname": "Nom",
+ "ask_lastname": "Cognom",
+ "ask_list_to_remove": "Llista per a suprimir",
+ "ask_main_domain": "Domini principal",
+ "ask_new_admin_password": "Nova contrasenya d'administrador",
+ "ask_password": "Contrasenya",
+ "ask_path": "Camí",
+ "backup_abstract_method": "Encara no s'ha implementat aquest mètode de copia de seguretat",
+ "backup_action_required": "S'ha d'especificar què s'ha de guardar",
+ "backup_app_failed": "No s'ha pogut fer la còpia de seguretat de l'aplicació \"{app:s}\"",
+ "backup_applying_method_borg": "Enviant tots els fitxers de la còpia de seguretat al repositori borg-backup...",
+ "backup_applying_method_copy": "Còpia de tots els fitxers a la còpia de seguretat...",
+ "backup_applying_method_custom": "Crida del mètode de còpia de seguretat personalitzat \"{method:s}\"...",
+ "backup_applying_method_tar": "Creació de l'arxiu tar de la còpia de seguretat...",
+ "backup_archive_app_not_found": "L'aplicació \"{app:s}\" no es troba dins l'arxiu de la còpia de seguretat",
+ "backup_archive_broken_link": "No s'ha pogut accedir a l'arxiu de la còpia de seguretat (enllaç invàlid cap a {path:s})",
+ "backup_archive_mount_failed": "No s'ha pogut carregar l'arxiu de la còpia de seguretat",
+ "backup_archive_name_exists": "Ja hi ha una còpia de seguretat amb aquest nom",
+ "backup_archive_name_unknown": "Còpia de seguretat local \"{name:s}\" desconeguda",
+ "backup_archive_open_failed": "No s'ha pogut obrir l'arxiu de la còpia de seguretat",
+ "backup_archive_system_part_not_available": "La part \"{part:s}\" del sistema no està disponible en aquesta copia de seguretat",
+ "backup_archive_writing_error": "No es poden afegir arxius a l'arxiu comprimit de la còpia de seguretat",
+ "backup_ask_for_copying_if_needed": "Alguns fitxers no s'han pogut preparar per la còpia de seguretat utilitzant el mètode que evita malgastar espai del sistema temporalment. Per fer la còpia de seguretat, s'han d'utilitzar {size:s}MB temporalment. Hi esteu d'acord?",
+ "backup_borg_not_implemented": "El mètode de còpia de seguretat Borg encara no està implementat",
+ "backup_cant_mount_uncompress_archive": "No es pot carregar en mode de lectura només el directori de l'arxiu descomprimit",
+ "backup_cleaning_failed": "No s'ha pogut netejar el directori temporal de la còpia de seguretat",
+ "backup_copying_to_organize_the_archive": "Copiant {size:s}MB per organitzar l'arxiu",
+ "backup_couldnt_bind": "No es pot lligar {src:s} amb {dest:s}.",
+ "backup_created": "S'ha creat la còpia de seguretat",
+ "backup_creating_archive": "Creant l'arxiu de la còpia de seguretat"
}
From 5ec499e75827fb6158e4c403cf31756c3ae9dfef Mon Sep 17 00:00:00 2001
From: Weblate
Date: Sun, 17 Mar 2019 12:46:20 +0000
Subject: [PATCH 126/199] Added translation using Weblate (Greek)
---
locales/el.json | 1 +
1 file changed, 1 insertion(+)
create mode 100644 locales/el.json
diff --git a/locales/el.json b/locales/el.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/locales/el.json
@@ -0,0 +1 @@
+{}
From aa0c1985d08a5ce4c236b6d2d6ce180f3ddd4459 Mon Sep 17 00:00:00 2001
From: Weblate
Date: Sun, 17 Mar 2019 12:47:04 +0000
Subject: [PATCH 127/199] Added translation using Weblate (Polish)
---
locales/pl.json | 1 +
1 file changed, 1 insertion(+)
create mode 100644 locales/pl.json
diff --git a/locales/pl.json b/locales/pl.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/locales/pl.json
@@ -0,0 +1 @@
+{}
From b5909d7d3445fc845daf5f11444b62ca20f6ebe2 Mon Sep 17 00:00:00 2001
From: Weblate
Date: Sun, 17 Mar 2019 12:47:38 +0000
Subject: [PATCH 128/199] Added translation using Weblate (Swedish)
---
locales/sv.json | 1 +
1 file changed, 1 insertion(+)
create mode 100644 locales/sv.json
diff --git a/locales/sv.json b/locales/sv.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/locales/sv.json
@@ -0,0 +1 @@
+{}
From b9fe9cb3a569e6a451f733142726db979194ba12 Mon Sep 17 00:00:00 2001
From: Weblate
Date: Sun, 17 Mar 2019 12:49:23 +0000
Subject: [PATCH 129/199] Added translation using Weblate (Chinese
(Simplified))
---
locales/zh_Hans.json | 1 +
1 file changed, 1 insertion(+)
create mode 100644 locales/zh_Hans.json
diff --git a/locales/zh_Hans.json b/locales/zh_Hans.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/locales/zh_Hans.json
@@ -0,0 +1 @@
+{}
From 18e7be1bc1459cbc6a5f3e234c56214005fee6d4 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Mon, 18 Mar 2019 07:57:28 +0100
Subject: [PATCH 130/199] Update psql
---
data/helpers.d/psql | 1 +
1 file changed, 1 insertion(+)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index a9ea5dadc..2212d692a 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -134,6 +134,7 @@ ynh_psql_dump_db() {
#
# usage: ynh_psql_create_user user pwd
# | arg: user - the user name to create
+# | arg: pwd - the password to identify user by
#
# Requires YunoHost version 3.?.? or higher.
ynh_psql_create_user() {
From 54e570ea175e8df02b97fffaa7cbd78b8538eb90 Mon Sep 17 00:00:00 2001
From: ppr
Date: Sun, 17 Mar 2019 16:48:47 +0000
Subject: [PATCH 131/199] Translated using Weblate (French)
Currently translated at 99.8% (503 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
---
locales/fr.json | 332 +++++++++++++++++++++++++++---------------------
1 file changed, 187 insertions(+), 145 deletions(-)
diff --git a/locales/fr.json b/locales/fr.json
index 7119039db..b864c5ac7 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -5,29 +5,29 @@
"admin_password_changed": "Le mot de passe d’administration a été modifié",
"app_already_installed": "{app:s} est déjà installé",
"app_argument_choice_invalid": "Choix invalide pour le paramètre « {name:s} », il doit être l’un de {choices:s}",
- "app_argument_invalid": "Valeur invalide pour le paramètre « {name:s} » : {error:s}",
+ "app_argument_invalid": "Valeur invalide pour le paramètre `{name:s}` : {error:s}",
"app_argument_missing": "Paramètre manquant « {:s} »",
- "app_argument_required": "Le paramètre « {name:s} » est requis",
+ "app_argument_required": "Le paramètre `{name:s}` est requis",
"app_extraction_failed": "Impossible d’extraire les fichiers d’installation",
- "app_id_invalid": "Id d’application incorrect",
+ "app_id_invalid": "Identifiant d’application invalide",
"app_incompatible": "L’application {app} est incompatible avec votre version de YunoHost",
"app_install_files_invalid": "Fichiers d’installation incorrects",
- "app_location_already_used": "L’application « {app} » est déjà installée à cet emplacement ({path})",
- "app_location_install_failed": "Impossible d’installer l’application à cet emplacement pour cause de conflit avec l’app « {other_app} » déjà installée sur « {other_path} »",
+ "app_location_already_used": "L’application '{app}' est déjà installée à cet emplacement ({path})",
+ "app_location_install_failed": "Impossible d’installer l’application à cet emplacement pour cause de conflit avec l’application '{other_app}' déjà installée sur '{other_path}'",
"app_manifest_invalid": "Manifeste d’application incorrect : {error}",
"app_no_upgrade": "Aucune application à mettre à jour",
"app_not_correctly_installed": "{app:s} semble être mal installé",
"app_not_installed": "{app:s} n’est pas installé",
"app_not_properly_removed": "{app:s} n’a pas été supprimé correctement",
- "app_package_need_update": "Le paquet de l’application {app} doit être mis à jour pour suivre les changements de YunoHost",
+ "app_package_need_update": "Le paquet de l’application {app} doit être mis à jour pour être en adéquation avec les changements de YunoHost",
"app_recent_version_required": "{app:s} nécessite une version plus récente de YunoHost",
"app_removed": "{app:s} a été supprimé",
- "app_requirements_checking": "Vérification des paquets requis pour {app}...",
+ "app_requirements_checking": "Vérification des paquets requis pour {app} …",
"app_requirements_failed": "Impossible de satisfaire les pré-requis pour {app} : {error}",
"app_requirements_unmeet": "Les pré-requis de {app} ne sont pas satisfaits, le paquet {pkgname} ({version}) doit être {spec}",
"app_sources_fetch_failed": "Impossible de récupérer les fichiers sources",
"app_unknown": "Application inconnue",
- "app_unsupported_remote_type": "Le type distant utilisé par l’application n’est pas pris en charge",
+ "app_unsupported_remote_type": "Ce type de commande à distance utilisé pour cette application n'est pas supporté",
"app_upgrade_failed": "Impossible de mettre à jour {app:s}",
"app_upgraded": "{app:s} a été mis à jour",
"appslist_fetched": "La liste d’applications {appslist:s} a été récupérée",
@@ -44,35 +44,35 @@
"ask_password": "Mot de passe",
"backup_action_required": "Vous devez préciser ce qui est à sauvegarder",
"backup_app_failed": "Impossible de sauvegarder l’application « {app:s} »",
- "backup_archive_app_not_found": "L’application « {app:s} » n’a pas été trouvée dans l’archive de la sauvegarde",
+ "backup_archive_app_not_found": "L’application '{app:s}' n’a pas été trouvée dans l’archive de la sauvegarde",
"backup_archive_hook_not_exec": "Le script « {hook:s} » n'a pas été exécuté dans cette sauvegarde",
"backup_archive_name_exists": "Une archive de sauvegarde avec ce nom existe déjà",
- "backup_archive_name_unknown": "L’archive locale de sauvegarde nommée « {name:s} » est inconnue",
+ "backup_archive_name_unknown": "L’archive locale de sauvegarde nommée '{name:s}' est inconnue",
"backup_archive_open_failed": "Impossible d’ouvrir l’archive de sauvegarde",
"backup_cleaning_failed": "Impossible de nettoyer le dossier temporaire de sauvegarde",
"backup_created": "Sauvegarde terminée",
- "backup_creating_archive": "Création de l’archive de sauvegarde...",
+ "backup_creating_archive": "Création de l’archive de sauvegarde …",
"backup_creation_failed": "Impossible de créer la sauvegarde",
- "backup_delete_error": "Impossible de supprimer « {path:s} »",
+ "backup_delete_error": "Impossible de supprimer '{path:s}'",
"backup_deleted": "La sauvegarde a été supprimée",
- "backup_extracting_archive": "Extraction de l’archive de sauvegarde...",
- "backup_hook_unknown": "Script de sauvegarde « {hook:s} » inconnu",
- "backup_invalid_archive": "Archive de sauvegarde incorrecte",
+ "backup_extracting_archive": "Extraction de l’archive de sauvegarde …",
+ "backup_hook_unknown": "Script de sauvegarde '{hook:s}' inconnu",
+ "backup_invalid_archive": "Archive de sauvegarde invalide",
"backup_nothings_done": "Il n’y a rien à sauvegarder",
- "backup_output_directory_forbidden": "Dossier de destination interdit. Les sauvegardes ne peuvent être créées dans les dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives",
+ "backup_output_directory_forbidden": "Dossier de destination interdit. Les sauvegardes ne peuvent être créées dans les sous-dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives",
"backup_output_directory_not_empty": "Le dossier de sortie n’est pas vide",
"backup_output_directory_required": "Vous devez spécifier un dossier de sortie pour la sauvegarde",
"backup_running_app_script": "Lancement du script de sauvegarde de l’application « {app:s} »...",
- "backup_running_hooks": "Exécution des scripts de sauvegarde...",
- "custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application locale {app:s}",
- "custom_appslist_name_required": "Vous devez spécifier un nom pour votre liste d’applications personnalisée",
+ "backup_running_hooks": "Exécution des scripts de sauvegarde …",
+ "custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application personnalisée {app:s}",
+ "custom_appslist_name_required": "Vous devez spécifier un nom pour votre liste d’applications personnalisées",
"diagnosis_debian_version_error": "Impossible de déterminer la version de Debian : {error}",
"diagnosis_kernel_version_error": "Impossible de récupérer la version du noyau : {error}",
"diagnosis_monitor_disk_error": "Impossible de superviser les disques : {error}",
"diagnosis_monitor_network_error": "Impossible de superviser le réseau : {error}",
"diagnosis_monitor_system_error": "Impossible de superviser le système : {error}",
"diagnosis_no_apps": "Aucune application installée",
- "dnsmasq_isnt_installed": "dnsmasq ne semble pas être installé, veuillez lancer « apt-get remove bind9 && apt-get install dnsmasq »",
+ "dnsmasq_isnt_installed": "dnsmasq ne semble pas être installé, veuillez lancer 'apt-get remove bind9 && apt-get install dnsmasq'",
"domain_cert_gen_failed": "Impossible de générer le certificat",
"domain_created": "Le domaine a été créé",
"domain_creation_failed": "Impossible de créer le domaine",
@@ -87,41 +87,41 @@
"domain_zone_exists": "Le fichier de zone DNS existe déjà",
"domain_zone_not_found": "Fichier de zone DNS introuvable pour le domaine {:s}",
"done": "Terminé",
- "downloading": "Téléchargement...",
+ "downloading": "Téléchargement en cours …",
"dyndns_cron_installed": "La tâche cron pour le domaine DynDNS a été installée",
- "dyndns_cron_remove_failed": "Impossible d’enlever la tâche cron pour le domaine DynDNS",
+ "dyndns_cron_remove_failed": "Impossible de supprimer la tâche cron pour le domaine DynDNS",
"dyndns_cron_removed": "La tâche cron pour le domaine DynDNS a été enlevée",
"dyndns_ip_update_failed": "Impossible de mettre à jour l’adresse IP sur le domaine DynDNS",
"dyndns_ip_updated": "Votre adresse IP a été mise à jour pour le domaine DynDNS",
- "dyndns_key_generating": "La clé DNS est en cours de génération, cela peut prendre du temps...",
+ "dyndns_key_generating": "La clé DNS est en cours de génération, cela peut prendre un certain temps …",
"dyndns_key_not_found": "Clé DNS introuvable pour le domaine",
"dyndns_no_domain_registered": "Aucun domaine n’a été enregistré avec DynDNS",
"dyndns_registered": "Le domaine DynDNS a été enregistré",
"dyndns_registration_failed": "Impossible d’enregistrer le domaine DynDNS : {error:s}",
"dyndns_unavailable": "Le domaine {domain:s} est indisponible.",
- "executing_command": "Exécution de la commande « {command:s} »...",
- "executing_script": "Exécution du script « {script:s} »...",
- "extracting": "Extraction...",
- "field_invalid": "Champ incorrect : « {:s} »",
+ "executing_command": "Exécution de la commande '{command:s}' …",
+ "executing_script": "Exécution du script '{script:s}' …",
+ "extracting": "Extraction en cours …",
+ "field_invalid": "Champ incorrect : '{:s}'",
"firewall_reload_failed": "Impossible de recharger le pare-feu",
"firewall_reloaded": "Le pare-feu a été rechargé",
"firewall_rules_cmd_failed": "Certaines règles du pare-feu n’ont pas pu être appliquées. Pour plus d’informations, consultez le journal.",
"format_datetime_short": "%d/%m/%Y %H:%M",
"hook_argument_missing": "Argument manquant : '{:s}'",
"hook_choice_invalid": "Choix incorrect : '{:s}'",
- "hook_exec_failed": "Échec de l’exécution du script « {path:s} »",
- "hook_exec_not_terminated": "L’exécution du script « {path:s} » ne s’est pas terminée",
+ "hook_exec_failed": "Échec de l’exécution du script : {path:s}",
+ "hook_exec_not_terminated": "L’exécution du script {path:s} ne s’est pas terminée correctement",
"hook_list_by_invalid": "La propriété de tri des actions est invalide",
- "hook_name_unknown": "Nom de script « {name:s} » inconnu",
+ "hook_name_unknown": "Nom de l'action '{name:s}' inconnu",
"installation_complete": "Installation terminée",
"installation_failed": "Échec de l’installation",
"ip6tables_unavailable": "Vous ne pouvez pas jouer avec ip6tables ici. Vous êtes soit dans un conteneur, soit votre noyau ne le prend pas en charge",
"iptables_unavailable": "Vous ne pouvez pas jouer avec iptables ici. Vous êtes soit dans un conteneur, soit votre noyau ne le prend pas en charge",
"ldap_initialized": "L’annuaire LDAP a été initialisé",
"license_undefined": "indéfinie",
- "mail_alias_remove_failed": "Impossible de supprimer l’alias courriel « {mail:s} »",
- "mail_domain_unknown": "Le domaine « {domain:s} » du courriel est inconnu",
- "mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert « {mail:s} »",
+ "mail_alias_remove_failed": "Impossible de supprimer l’alias courriel '{mail:s}'",
+ "mail_domain_unknown": "Le domaine '{domain:s}' du courriel est inconnu",
+ "mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert '{mail:s}'",
"maindomain_change_failed": "Impossible de modifier le domaine principal",
"maindomain_changed": "Le domaine principal a été modifié",
"monitor_disabled": "La supervision du serveur a été désactivé",
@@ -153,7 +153,7 @@
"packages_upgrade_critical_later": "Les paquets critiques ({packages:s}) seront mis à jour ultérieurement",
"packages_upgrade_failed": "Impossible de mettre à jour tous les paquets",
"path_removal_failed": "Impossible de supprimer le chemin {:s}",
- "pattern_backup_archive_name": "Doit être un nom de fichier valide composé uniquement de caractères alphanumériques et de -_.",
+ "pattern_backup_archive_name": "Doit être un nom de fichier valide avec un maximum de 30 caractères, et composé uniquement de caractères alphanumériques et de tirets tels que - et _",
"pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.org)",
"pattern_email": "Doit être une adresse courriel valide (ex. : pseudo@domain.org)",
"pattern_firstname": "Doit être un prénom valide",
@@ -178,8 +178,8 @@
"restore_failed": "Impossible de restaurer le système",
"restore_hook_unavailable": "Le script de restauration « {part:s} » n’est pas disponible sur votre système, et n’est pas non plus dans l’archive",
"restore_nothings_done": "Rien n’a été restauré",
- "restore_running_app_script": "Lancement du script de restauration pour l’application « {app:s} »...",
- "restore_running_hooks": "Exécution des scripts de restauration...",
+ "restore_running_app_script": "Exécution du script de restauration de l'application '{app:s}' .…",
+ "restore_running_hooks": "Exécution des scripts de restauration …",
"service_add_configuration": "Ajout du fichier de configuration {file:s}",
"service_add_failed": "Impossible d’ajouter le service « {service:s} »",
"service_added": "Le service « {service:s} » a été ajouté",
@@ -228,9 +228,9 @@
"unlimit": "Pas de quota",
"unrestore_app": "L’application « {app:s} » ne sera pas restaurée",
"update_cache_failed": "Impossible de mettre à jour le cache de l’APT",
- "updating_apt_cache": "Mise à jour de la liste des paquets disponibles...",
+ "updating_apt_cache": "Récupération des mises à jour disponibles pour les paquets du système .…",
"upgrade_complete": "Mise à jour terminée",
- "upgrading_packages": "Mise à jour des paquets...",
+ "upgrading_packages": "Mise à jour des paquets en cours …",
"upnp_dev_not_found": "Aucun périphérique compatible UPnP n’a été trouvé",
"upnp_disabled": "UPnP a été désactivé",
"upnp_enabled": "UPnP a été activé",
@@ -247,98 +247,98 @@
"yunohost_already_installed": "YunoHost est déjà installé",
"yunohost_ca_creation_failed": "Impossible de créer l’autorité de certification",
"yunohost_configured": "YunoHost a été configuré",
- "yunohost_installing": "Installation de YunoHost...",
+ "yunohost_installing": "Installation de YunoHost en cours …",
"yunohost_not_installed": "YunoHost n’est pas ou pas correctement installé. Veuillez exécuter « yunohost tools postinstall »",
- "certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner)",
- "certmanager_domain_unknown": "Domaine inconnu {domain:s}",
- "certmanager_domain_cert_not_selfsigned": "Le certificat du domaine {domain:s} n’est pas auto-signé. Voulez-vous vraiment le remplacer ? (Utilisez --force)",
- "certmanager_certificate_fetching_or_enabling_failed": "Il semble que l’activation du nouveau certificat pour {domain:s} a échoué…",
- "certmanager_attempt_to_renew_nonLE_cert": "Le certificat pour le domaine {domain:s} n’est pas fourni par Let’s Encrypt. Impossible de le renouveler automatiquement !",
- "certmanager_attempt_to_renew_valid_cert": "Le certificat pour le domaine {domain:s} est sur le point d’expirer ! Utilisez --force pour contourner",
- "certmanager_domain_http_not_working": "Il semble que le domaine {domain:s} n’est pas accessible via HTTP. Veuillez vérifier que vos configuration DNS et nginx sont correctes",
- "certmanager_error_no_A_record": "Aucun enregistrement DNS « A » n’a été trouvé pour {domain:s}. De devez faire pointer votre nom de domaine vers votre machine pour être capable d’installer un certificat Let’s Encrypt ! (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
- "certmanager_domain_dns_ip_differs_from_public_ip": "L’enregistrement DNS « A » du domaine {domain:s} est différent de l’adresse IP de ce serveur. Si vous avez modifié récemment votre enregistrement « A », veuillez attendre sa propagation (quelques vérificateur de propagation sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
- "certmanager_cannot_read_cert": "Quelque chose s’est mal passé lors de la tentative d’ouverture du certificat actuel pour le domaine {domain:s} (fichier : {file:s}), cause : {reason:s}",
+ "certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de vouloir remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner cela)",
+ "certmanager_domain_unknown": "Domaine {domain:s} inconnu",
+ "certmanager_domain_cert_not_selfsigned": "Le certificat du domaine {domain:s} n’est pas auto-signé. Voulez-vous vraiment le remplacer ? (Utilisez --force pour cela)",
+ "certmanager_certificate_fetching_or_enabling_failed": "Il semble que l’activation du nouveau certificat pour {domain:s} a échoué …",
+ "certmanager_attempt_to_renew_nonLE_cert": "Le certificat pour le domaine {domain:s} n’est pas émis par Let’s Encrypt. Impossible de le renouveler automatiquement !",
+ "certmanager_attempt_to_renew_valid_cert": "Le certificat pour le domaine {domain:s} est sur le point d’expirer ! Utilisez --force pour contourner cela",
+ "certmanager_domain_http_not_working": "Il semble que le domaine {domain:s} n’est pas accessible via HTTP. Veuillez vérifier que vos configuration DNS et Nginx sont correctes",
+ "certmanager_error_no_A_record": "Aucun enregistrement DNS 'A' n’a été trouvé pour {domain:s}. Vous devez faire pointer votre nom de domaine vers votre machine pour être en mesure d’installer un certificat Let’s Encrypt ! (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
+ "certmanager_domain_dns_ip_differs_from_public_ip": "L’enregistrement DNS 'A' du domaine {domain:s} est différent de l’adresse IP de ce serveur. Si vous avez récemment modifié votre enregistrement 'A', veuillez attendre sa propagation (quelques vérificateur de propagation DNS sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
+ "certmanager_cannot_read_cert": "Quelque chose s’est mal passé lors de la tentative d’ouverture du certificat actuel pour le domaine {domain:s} (fichier : {file:s}), la cause est : {reason:s}",
"certmanager_cert_install_success_selfsigned": "Installation avec succès d’un certificat auto-signé pour le domaine {domain:s} !",
"certmanager_cert_install_success": "Installation avec succès d’un certificat Let’s Encrypt pour le domaine {domain:s} !",
"certmanager_cert_renew_success": "Renouvellement avec succès d’un certificat Let’s Encrypt pour le domaine {domain:s} !",
"certmanager_old_letsencrypt_app_detected": "\nYunoHost a détecté que l’application « letsencrypt » est installé, ce qui est en conflit avec les nouvelles fonctionnalités de gestion intégrée de certificats dans YunoHost. Si vous souhaitez utiliser ces nouvelles fonctionnalités intégrées, veuillez lancer les commandes suivantes pour migrer votre installation :\n\n yunohost app remove letsencrypt\n yunohost domain cert-install\n\nN.B. : cela tentera de réinstaller les certificats de tous les domaines avec un certificat Let's Encrypt ou ceux auto-signés",
"certmanager_cert_signing_failed": "La signature du nouveau certificat a échoué",
"certmanager_no_cert_file": "Impossible de lire le fichier de certificat pour le domaine {domain:s} (fichier : {file:s})",
- "certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour de défi ACME : le fichier de configuration nginx {filepath:s} est en conflit et doit être retiré au préalable",
- "certmanager_hit_rate_limit": "Trop de certificats ont déjà été demandés récemment pour cet ensemble précis de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails",
+ "certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration Nginx {filepath:s} est en conflit et doit être préalablement retiré",
+ "certmanager_hit_rate_limit": "Trop de certificats ont déjà été émis récemment pour ce même ensemble de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails sur les ratios et limitations",
"ldap_init_failed_to_create_admin": "L’initialisation de LDAP n’a pas réussi à créer l’utilisateur admin",
"ssowat_persistent_conf_read_error": "Erreur lors de la lecture de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
"ssowat_persistent_conf_write_error": "Erreur lors de la sauvegarde de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
- "domain_cannot_remove_main": "Impossible de retirer le domaine principal. Définissez un nouveau domaine principal au préalable.",
+ "domain_cannot_remove_main": "Impossible de supprimer le domaine principal. Commencez par définir un nouveau domaine principal",
"certmanager_self_ca_conf_file_not_found": "Le fichier de configuration pour l’autorité du certificat auto-signé est introuvable (fichier : {file:s})",
"certmanager_unable_to_parse_self_CA_name": "Impossible d’analyser le nom de l’autorité du certificat auto-signé (fichier : {file:s})",
- "mailbox_used_space_dovecot_down": "Le service de mail Dovecot doit être démarré, si vous souhaitez voir l’espace disque occupé par la messagerie",
+ "mailbox_used_space_dovecot_down": "Le service mail Dovecot doit être démarré, si vous souhaitez voir l’espace disque occupé par la messagerie",
"domains_available": "Domaines disponibles :",
"backup_archive_broken_link": "Impossible d’accéder à l’archive de sauvegarde (lien invalide vers {path:s})",
- "certmanager_acme_not_configured_for_domain": "Le certificat du domaine {domain:s} ne semble pas être correctement installé. Veuillez préalablement exécuter cert-install pour ce domaine.",
- "certmanager_domain_not_resolved_locally": "Le domaine {domain:s} ne peut être déterminé depuis votre serveur YunoHost. Cela peut arriver si vous avez récemment modifié votre enregistrement DNS. Auquel cas, merci d’attendre quelques heures qu’il se propage. Si le problème persiste, envisager d’ajouter {domain:s} au fichier /etc/hosts. (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces vérifications.)",
- "certmanager_http_check_timeout": "Expiration du délai lors de la tentative du serveur de se contacter via HTTP en utilisant son adresse IP publique (domaine {domain:s} avec l’IP {ip:s}). Vous rencontrez peut-être un problème d’hairpinning ou alors le pare-feu/routeur en amont de votre serveur est mal configuré.",
- "certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Let’s Encrypt. L’installation/le renouvellement du certificat a été interrompu - veuillez réessayer prochainement.",
+ "certmanager_acme_not_configured_for_domain": "Le certificat du domaine {domain:s} ne semble pas être correctement installé. Veuillez d'abord exécuter cert-install.",
+ "certmanager_domain_not_resolved_locally": "Le domaine {domain:s} ne peut être résolu depuis votre serveur YunoHost. Cela peut se produire si vous avez récemment modifié votre enregistrement DNS. Si c'est le cas, merci d’attendre quelques heures qu’il se propage. Si le problème persiste, envisager d’ajouter {domain:s} au fichier /etc/hosts. (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces vérifications.)",
+ "certmanager_http_check_timeout": "Expiration du délai lorsque le serveur a essayé de se contacter lui-même via HTTP en utilisant l'adresse IP public {ip:s} du domaine {domain:s}. Vous rencontrez peut-être un problème d’hairpinning ou alors le pare-feu/routeur en amont de votre serveur est mal configuré.",
+ "certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Let’s Encrypt. L’installation ou le renouvellement du certificat a été annulé - veuillez réessayer plus tard.",
"appslist_retrieve_bad_format": "Le fichier récupéré pour la liste d’applications {appslist:s} n’est pas valide",
"domain_hostname_failed": "Échec de la création d’un nouveau nom d’hôte",
"yunohost_ca_creation_success": "L’autorité de certification locale a été créée.",
"appslist_name_already_tracked": "Il y a déjà une liste d’applications enregistrée avec le nom {name:s}.",
"appslist_url_already_tracked": "Il y a déjà une liste d’applications enregistrée avec l’URL {url:s}.",
- "appslist_migrating": "Migration de la liste d’applications {appslist:s}…",
- "appslist_could_not_migrate": "Impossible de migrer la liste {appslist:s} ! Impossible d’exploiter l’URL… L’ancienne tâche cron a été conservée dans {bkp_file:s}.",
+ "appslist_migrating": "Migration de la liste d’applications {appslist:s} …",
+ "appslist_could_not_migrate": "Impossible de migrer la liste {appslist:s} ! Impossible d’exploiter l’URL. L’ancienne tâche programmée a été conservée dans {bkp_file:s}.",
"appslist_corrupted_json": "Impossible de charger la liste d’applications. Il semble que {filename:s} soit corrompu.",
- "app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Regardez avec « app changeurl » si c’est disponible.",
+ "app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Regardez avec `app changeurl` si c’est disponible.",
"app_change_no_change_url_script": "L’application {app_name:s} ne prend pas encore en charge le changement d’URL, vous pourriez avoir besoin de la mettre à jour.",
- "app_change_url_failed_nginx_reload": "Le redémarrage de nginx a échoué. Voici la sortie de « nginx -t » :\n{nginx_errors:s}",
- "app_change_url_identical_domains": "L’ancien et le nouveau couple domaine/chemin sont identiques pour {domain:s}{path:s}, aucune action.",
- "app_change_url_no_script": "L’application {app_name:s} ne prend pas encore en charge le changement d’URL. Vous devriez peut-être la mettre à jour.",
+ "app_change_url_failed_nginx_reload": "Le redémarrage de nginx a échoué. Voici la sortie de `nginx -t` :\n{nginx_errors:s}",
+ "app_change_url_identical_domains": "L’ancien et le nouveau couple domaine/chemin_de_l'URL sont identiques pour (`{domain:s}{path:s}`), rien à faire.",
+ "app_change_url_no_script": "L’application `{app_name:s}` ne prend pas encore en charge le changement d’URL. Vous devriez peut-être la mettre à jour.",
"app_change_url_success": "L’URL de l’application {app:s} a été changée en {domain:s}{path:s}",
"app_location_unavailable": "Cette URL n’est pas disponible ou est en conflit avec une application existante\n{apps:s}",
"app_already_up_to_date": "{app:s} est déjà à jour",
"invalid_url_format": "Format d’URL non valide",
- "global_settings_bad_choice_for_enum": "La valeur du paramètre {setting:s} est incorrecte. Reçu : {received_type:s}; attendu : {expected_type:s}",
- "global_settings_bad_type_for_setting": "Le type du paramètre {setting:s} est incorrect. Reçu : {received_type:s}; attendu : {expected_type:s}.",
- "global_settings_cant_open_settings": "Échec de l’ouverture du ficher de configurations, cause : {reason:s}",
+ "global_settings_bad_choice_for_enum": "La valeur du paramètre {setting:s} est incorrecte. Reçu : {received_type:s} mais attendu : {expected_type:s}",
+ "global_settings_bad_type_for_setting": "Le type du paramètre {setting:s} est incorrect. Reçu : {received_type:s} mais attendu : {expected_type:s}",
+ "global_settings_cant_open_settings": "Échec de l’ouverture du ficher de configurations car : {reason:s}",
"global_settings_cant_serialize_setings": "Échec de sérialisation des données de configurations, cause : {reason:s}",
- "global_settings_cant_write_settings": "Échec d’écriture du fichier de configurations, cause : {reason:s}",
- "global_settings_key_doesnt_exists": "La clef « {settings_key:s} » n’existe pas dans les configurations globales, vous pouvez voir toutes les clefs disponibles en saisissant « yunohost settings list »",
+ "global_settings_cant_write_settings": "Échec d’écriture du fichier de configurations car : {reason:s}",
+ "global_settings_key_doesnt_exists": "La clef '{settings_key:s}' n’existe pas dans les configurations générales, vous pouvez voir toutes les clefs disponibles en saisissant 'yunohost settings list'",
"global_settings_reset_success": "Réussite ! Vos configurations précédentes ont été sauvegardées dans {path:s}",
"global_settings_setting_example_bool": "Exemple d’option booléenne",
"global_settings_setting_example_int": "Exemple d’option de type entier",
"global_settings_setting_example_string": "Exemple d’option de type chaîne",
"global_settings_setting_example_enum": "Exemple d’option de type énumération",
- "global_settings_unknown_type": "Situation inattendue, la configuration {setting:s} semble avoir le type {unknown_type:s} mais ce n’est pas un type pris en charge par le système.",
- "global_settings_unknown_setting_from_settings_file": "Clef inconnue dans les configurations : {setting_key:s}, rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
+ "global_settings_unknown_type": "Situation inattendue, la configuration {setting:s} semble avoir le type {unknown_type:s} mais celui-ci n'est pas pris en charge par le système.",
+ "global_settings_unknown_setting_from_settings_file": "Clef inconnue dans les paramètres : '{setting_key:s}', rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
"service_conf_file_kept_back": "Le fichier de configuration « {conf} » devrait être supprimé par le service {service} mais a été conservé.",
"backup_abstract_method": "Cette méthode de sauvegarde n’a pas encore été implémentée",
- "backup_applying_method_tar": "Création de l’archive tar de la sauvegarde…",
- "backup_applying_method_copy": "Copie de tous les fichiers dans la sauvegarde…",
- "backup_applying_method_borg": "Envoi de tous les fichiers dans la sauvegarde dans de référentiel borg-backup…",
- "backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée « {method:s} »…",
- "backup_archive_system_part_not_available": "La partie « {part:s} » du système n’est pas disponible dans cette sauvegarde",
+ "backup_applying_method_tar": "Création de l’archive tar de la sauvegarde …",
+ "backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder …",
+ "backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans de référentiel borg-backup …",
+ "backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée '{method:s}' …",
+ "backup_archive_system_part_not_available": "La partie '{part:s}' du système n’est pas disponible dans cette sauvegarde",
"backup_archive_mount_failed": "Le montage de l’archive de sauvegarde a échoué",
- "backup_archive_writing_error": "Impossible d’ajouter les fichiers à la sauvegarde dans l’archive compressée",
+ "backup_archive_writing_error": "Impossible d'ajouter des fichiers '{source:s}' (nommés dans l'archive : '{dest:s}') à sauvegarder dans l'archive compressée '{archive:s}'",
"backup_ask_for_copying_if_needed": "Certains fichiers n’ont pas pu être préparés pour être sauvegardés en utilisant la méthode qui évite temporairement de gaspiller de l’espace sur le système. Pour mener la sauvegarde, {size:s} Mo doivent être temporairement utilisés. Acceptez-vous ?",
- "backup_borg_not_implemented": "La méthode de sauvegarde Bord n’est pas encore implémentée",
+ "backup_borg_not_implemented": "La méthode de sauvegarde Borg n’est pas encore implémentée",
"backup_cant_mount_uncompress_archive": "Impossible de monter en lecture seule le dossier de l’archive décompressée",
- "backup_copying_to_organize_the_archive": "Copie de {size:s} Mio pour organiser l’archive",
+ "backup_copying_to_organize_the_archive": "Copie de {size:s} Mo pour organiser l’archive",
"backup_csv_creation_failed": "Impossible de créer le fichier CSV nécessaire aux opérations futures de restauration",
"backup_csv_addition_failed": "Impossible d’ajouter des fichiers à sauvegarder dans le fichier CSV",
- "backup_custom_need_mount_error": "Échec de la méthode de sauvegarde personnalisée à l’étape « need_mount »",
- "backup_custom_backup_error": "Échec de la méthode de sauvegarde personnalisée à l’étape « backup »",
- "backup_custom_mount_error": "Échec de la méthode de sauvegarde personnalisée à l’étape « mount »",
+ "backup_custom_need_mount_error": "Échec de la méthode de sauvegarde personnalisée à l’étape 'need_mount'",
+ "backup_custom_backup_error": "Échec de la méthode de sauvegarde personnalisée à l’étape 'backup'",
+ "backup_custom_mount_error": "Échec de la méthode de sauvegarde personnalisée à l’étape 'mount'",
"backup_no_uncompress_archive_dir": "Le dossier de l’archive décompressée n’existe pas",
"backup_method_tar_finished": "L’archive tar de la sauvegarde a été créée",
"backup_method_copy_finished": "La copie de la sauvegarde est terminée",
"backup_method_borg_finished": "La sauvegarde dans Borg est terminée",
- "backup_method_custom_finished": "La méthode se sauvegarde personnalisée « {method:s} » est terminée",
- "backup_system_part_failed": "Impossible de sauvegarder la partie « {part:s} » du système",
+ "backup_method_custom_finished": "La méthode de sauvegarde personnalisée '{method:s}' est terminée",
+ "backup_system_part_failed": "Impossible de sauvegarder la partie '{part:s}' du système",
"backup_unable_to_organize_files": "Impossible d’organiser les fichiers dans l’archive avec la méthode rapide",
"backup_with_no_backup_script_for_app": "L’application {app:s} n’a pas de script de sauvegarde. Ignorer.",
"backup_with_no_restore_script_for_app": "L’application {app:s} n’a pas de script de restauration, vous ne pourrez pas restaurer automatiquement la sauvegarde de cette application.",
- "global_settings_cant_serialize_settings": "Échec de la sérialisation des données de paramétrage, cause : {reason:s}",
+ "global_settings_cant_serialize_settings": "Échec de la sérialisation des données de paramétrage car : {reason:s}",
"restore_removing_tmp_dir_failed": "Impossible de sauvegarder un ancien dossier temporaire",
"restore_extracting": "Extraction des fichiers nécessaires depuis l’archive…",
"restore_mounting_archive": "Montage de l’archive dans « {path:s} »",
@@ -367,32 +367,32 @@
"app_upgrade_some_app_failed": "Impossible de mettre à jour certaines applications",
"ask_path": "Chemin",
"dyndns_could_not_check_provide": "Impossible de vérifier si {provider:s} peut fournir {domain:s}.",
- "dyndns_domain_not_provided": "Le fournisseur Dyndns {provider:s} ne peut pas fournir le domaine {domain:s}.",
- "app_make_default_location_already_used": "Impossible de configurer l’app « {app} » par défaut pour le domaine {domain}, déjà utilisé par l’autre app « {other_app} »",
- "app_upgrade_app_name": "Mise à jour de l’application {app}...",
- "backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives « {path:s} ». Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas, vous avez probablement oublié de monter ou de connecter votre disque / clef USB.",
+ "dyndns_domain_not_provided": "Le fournisseur DynDNS {provider:s} ne peut pas fournir le domaine {domain:s}.",
+ "app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine {domain} car déjà utilisé par l'application '{other_app}'",
+ "app_upgrade_app_name": "Mise à jour de l’application {app} …",
+ "backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives '{path:s}'. Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas, vous avez probablement oublié de monter ou de connecter votre disque dur ou votre clef USB.",
"migrate_tsig_end": "La migration à hmac-sha512 est terminée",
- "migrate_tsig_failed": "La migration du domaine dyndns {domain} à hmac-sha512 a échoué, annulation des modifications. Erreur : {error_code} - {error}",
+ "migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué, annulation des modifications. Erreur : {error_code} - {error}",
"migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine « {domain} », lancement de la migration vers hmac-sha512 qui est plus sécurisé",
- "migrate_tsig_wait": "Attendons 3 minutes pour que le serveur dyndns prenne en compte la nouvelle clef…",
- "migrate_tsig_wait_2": "2 minutes…",
- "migrate_tsig_wait_3": "1 minute…",
- "migrate_tsig_wait_4": "30 secondes…",
- "migrate_tsig_not_needed": "Il ne semble pas que vous utilisez un domaine dyndns, donc aucune migration n’est nécessaire !",
+ "migrate_tsig_wait": "Attendre 3 minutes pour que le serveur DynDNS prenne en compte la nouvelle clef …",
+ "migrate_tsig_wait_2": "2 minutes …",
+ "migrate_tsig_wait_3": "1 minute …",
+ "migrate_tsig_wait_4": "30 secondes …",
+ "migrate_tsig_not_needed": "Il ne semble pas que vous utilisez un domaine DynDNS, donc aucune migration n’est nécessaire !",
"app_checkurl_is_deprecated": "Packagers /!\\ 'app checkurl' est obsolète ! Utilisez 'app register-url' en remplacement !",
- "migration_description_0001_change_cert_group_to_sslcert": "Change les permissions de groupe des certificats de « metronome » à « ssl-cert »",
- "migration_description_0002_migrate_to_tsig_sha256": "Améliore la sécurité de DynDNDS TSIG en utilisant SHA512 au lieu de MD5",
+ "migration_description_0001_change_cert_group_to_sslcert": "Change les permissions de groupe des certificats de 'metronome' à 'ssl-cert'",
+ "migration_description_0002_migrate_to_tsig_sha256": "Améliore la sécurité de DynDNS TSIG en utilisant SHA512 au lieu de MD5",
"migration_description_0003_migrate_to_stretch": "Mise à niveau du système vers Debian Stretch et YunoHost 3.0",
"migration_0003_backward_impossible": "La migration Stretch n’est pas réversible.",
"migration_0003_start": "Démarrage de la migration vers Stretch. Les journaux seront disponibles dans {logfile}.",
- "migration_0003_patching_sources_list": "Modification de sources.lists…",
- "migration_0003_main_upgrade": "Démarrage de la mise à niveau principale…",
- "migration_0003_fail2ban_upgrade": "Démarrage de la mise à niveau de fail2ban…",
- "migration_0003_restoring_origin_nginx_conf": "Votre fichier /etc/nginx/nginx.conf a été modifié d’une manière ou d’une autre. La migration va d’abords le réinitialiser à son état initial… Le fichier précédent sera disponible en tant que {backup_dest}.",
- "migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du paquet YunoHost… La migration terminera, mais la mise à jour réelle aura lieu immédiatement après. Après cette opération terminée, vous pourriez avoir à vous reconnecter à l’administration web.",
+ "migration_0003_patching_sources_list": "Modification de sources.lists …",
+ "migration_0003_main_upgrade": "Démarrage de la mise à niveau principale …",
+ "migration_0003_fail2ban_upgrade": "Démarrage de la mise à niveau de fail2ban …",
+ "migration_0003_restoring_origin_nginx_conf": "Votre fichier /etc/nginx/nginx.conf a été modifié d’une manière ou d’une autre. La migration va d’abords le réinitialiser à son état initial. Le fichier précédent sera disponible en tant que {backup_dest}.",
+ "migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du paquet YunoHost. La migration se terminera, mais la mise à jour réelle aura lieu immédiatement après. Après cette opération terminée, vous pourriez avoir à vous reconnecter à l’administration via le panel web.",
"migration_0003_not_jessie": "La distribution Debian actuelle n’est pas Jessie !",
"migration_0003_system_not_fully_up_to_date": "Votre système n’est pas complètement à jour. Veuillez mener une mise à jour classique avant de lancer à migration à Stretch.",
- "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est ma passé pendant la mise à niveau principale : le système est toujours sur Jessie ?!? Pour investiguer le problème, veuillez regarder {log} 🙁…",
+ "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est ma passé pendant la mise à niveau principale : le système est toujours sur Jessie ?!? Pour investiguer le problème, veuillez regarder les journaux {log} 🙁…",
"migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nDe plus, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence !",
"migration_0003_problematic_apps_warning": "Veuillez noter que les applications suivantes, éventuellement problématiques, ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées «working ». En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront après la mise à niveau : {problematic_apps}",
"migration_0003_modified_files": "Veuillez noter que les fichiers suivants ont été détectés comme modifiés manuellement et pourraient être écrasés à la fin de la mise à niveau : {manually_modified_files}",
@@ -417,49 +417,49 @@
"service_description_ssh": "vous permet de vous connecter à distance à votre serveur via un terminal (protocole SSH)",
"service_description_yunohost-api": "permet les interactions entre l’interface web de YunoHost et le système",
"service_description_yunohost-firewall": "gère les ports de connexion ouverts et fermés aux services",
- "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 faîtes.",
- "log_corrupted_md_file": "Le fichier yaml de metadata associé aux logs est corrompu : {md_file}",
- "log_category_404": "La catégorie de log « {category} » n’existe pas",
- "log_link_to_log": "Log complet de cette opération : « {desc} »",
- "log_help_to_get_log": "Pour voir le log de cette opération « {desc} », utiliser la commande « yunohost log display {name} »",
- "log_link_to_failed_log": "L’opération « {desc} » a échouée ! Pour avoir de l’aide, merci de fournir le log complet de l’opération",
- "backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge php7, la restauration de vos applications php peut ne pas aboutir (reason: {error:s})",
- "log_help_to_get_failed_log": "L’opération « {desc} » a échouée ! Pour avoir de l’aide, merci de partager le log de cette opération en utilisant la commande « yunohost log display {name} --share »",
- "log_does_exists": "Il n’existe pas de log de l’opération ayant pour nom « {log} », utiliser « yunohost log list pour voir tous les fichiers de logs disponibles »",
+ "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 metadata associé aux logs est corrompu : {md_file}",
+ "log_category_404": "Le journal de la catégorie '{category}' n’existe pas",
+ "log_link_to_log": "Log complet de cette opération : ' {desc} '",
+ "log_help_to_get_log": "Pour voir le log de cette opération '{desc}', utiliser la commande 'yunohost log display {name}'",
+ "log_link_to_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de fournir le log complet de l’opération en cliquant ici",
+ "backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge php7, vos applications php pourraient ne pas être restaurées (reason: {error:s})",
+ "log_help_to_get_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de partager le log de cette opération en utilisant la commande 'yunohost log display {name} --share'",
+ "log_does_exists": "Il n’existe pas de log de l’opération ayant pour nom '{log}', utiliser 'yunohost log list pour voir tous les fichiers de logs disponibles'",
"log_operation_unit_unclosed_properly": "L’opération ne s’est pas terminée correctement",
- "log_app_addaccess": "Ajouter l’accès à « {} »",
- "log_app_removeaccess": "Enlever l’accès à « {} »",
- "log_app_clearaccess": "Retirer tous les accès à « {} »",
+ "log_app_addaccess": "Ajouter l’accès à '{}'",
+ "log_app_removeaccess": "Enlever l’accès à '{}'",
+ "log_app_clearaccess": "Retirer tous les accès à '{}'",
"log_app_fetchlist": "Ajouter une liste d’application",
"log_app_removelist": "Enlever une liste d’application",
- "log_app_change_url": "Changer l’url de l’application « {} »",
- "log_app_install": "Installer l’application « {} »",
- "log_app_remove": "Enlever l’application « {} »",
- "log_app_upgrade": "Mettre à jour l’application « {} »",
- "log_app_makedefault": "Faire de « {} » l’application par défaut",
+ "log_app_change_url": "Changer l’url de l’application '{}'",
+ "log_app_install": "Installer l’application '{}'",
+ "log_app_remove": "Enlever l’application '{}'",
+ "log_app_upgrade": "Mettre à jour l’application '{}'",
+ "log_app_makedefault": "Faire de '{}' l’application par défaut",
"log_available_on_yunopaste": "Le log est désormais disponible via {url}",
- "log_backup_restore_system": "Restaurer le système depuis une sauvegarde",
- "log_backup_restore_app": "Restaurer « {} » depuis une sauvegarde",
- "log_remove_on_failed_restore": "Retirer « {} » après la restauration depuis une sauvegarde qui a échouée",
- "log_remove_on_failed_install": "Enlever « {} » après une installation échouée",
- "log_domain_add": "Ajouter le domaine « {} » dans la configuration du système",
- "log_domain_remove": "Enlever le domaine « {} » de la configuration du système",
- "log_dyndns_subscribe": "Souscrire au sous-domaine « {} » de Yunohost",
- "log_dyndns_update": "Mettre à jour l’adresse ip associée à votre sous-domaine Yunohost « {} »",
- "log_letsencrypt_cert_install": "Installer le certificat Let’s encryt sur le domaine « {} »",
- "log_selfsigned_cert_install": "Installer le certificat auto-signé sur le domaine « {} »",
- "log_letsencrypt_cert_renew": "Renouveler le certificat Let’s encrypt de « {} »",
- "log_service_enable": "Activer le service « {} »",
- "log_service_regen_conf": "Régénérer la configuration système de « {} »",
- "log_user_create": "Ajouter l’utilisateur « {} »",
- "log_user_delete": "Enlever l’utilisateur « {} »",
- "log_user_update": "Mettre à jour les informations de l’utilisateur « {} »",
- "log_tools_maindomain": "Faire de « {} » le domaine principal",
- "log_tools_migrations_migrate_forward": "Migrer",
+ "log_backup_restore_system": "Restaurer le système depuis une archive de sauvegarde",
+ "log_backup_restore_app": "Restaurer '{}' depuis une sauvegarde",
+ "log_remove_on_failed_restore": "Retirer '{}' après la restauration depuis une sauvegarde qui a échouée",
+ "log_remove_on_failed_install": "Enlever '{}' après une installation échouée",
+ "log_domain_add": "Ajouter le domaine '{}' dans la configuration du système",
+ "log_domain_remove": "Enlever le domaine '{}' de la configuration du système",
+ "log_dyndns_subscribe": "Souscrire au sous-domaine YunoHost '{}'",
+ "log_dyndns_update": "Mettre à jour l’adresse IP associée à votre sous-domaine YunoHost '{}'",
+ "log_letsencrypt_cert_install": "Installer le certificat Let’s Encrypt sur le domaine '{}'",
+ "log_selfsigned_cert_install": "Installer le certificat auto-signé sur le domaine '{}'",
+ "log_letsencrypt_cert_renew": "Renouveler le certificat Let’s Encrypt de '{}'",
+ "log_service_enable": "Activer le service '{}'",
+ "log_service_regen_conf": "Régénérer la configuration système de '{}'",
+ "log_user_create": "Ajouter l’utilisateur '{}'",
+ "log_user_delete": "Supprimer l’utilisateur '{}'",
+ "log_user_update": "Mettre à jour les informations de l’utilisateur '{}'",
+ "log_tools_maindomain": "Faire de '{}' le domaine principal",
+ "log_tools_migrations_migrate_forward": "Migrer vers",
"log_tools_migrations_migrate_backward": "Revenir en arrière",
- "log_tools_postinstall": "Faire la post-installation du serveur Yunohost",
+ "log_tools_postinstall": "Faire la post-installation de votre serveur YunoHost",
"log_tools_upgrade": "Mise à jour des paquets Debian",
- "log_tools_shutdown": "Eteindre votre serveur",
+ "log_tools_shutdown": "Éteindre votre serveur",
"log_tools_reboot": "Redémarrer votre serveur",
"mail_unavailable": "Cette adresse mail est réservée et doit être automatiquement attribuée au tout premier utilisateur",
"migration_description_0004_php5_to_php7_pools": "Reconfigurez le pool PHP pour utiliser PHP 7 au lieu de 5",
@@ -471,14 +471,56 @@
"service_description_php7.0-fpm": "exécute des applications écrites en PHP avec nginx",
"users_available": "Liste des utilisateurs disponibles :",
"good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase de chiffrement) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
- "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase de chiffrement) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
+ "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères - bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou d'utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
"migration_0006_disclaimer": "Yunohost s’attend maintenant à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
"migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.",
- "password_listed": "Ce mot de passe est l’un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d’un peu plus unique.",
+ "password_listed": "Ce mot de passe est l'un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d'un peu plus unique.",
"password_too_simple_1": "Le mot de passe doit comporter au moins 8 caractères",
- "password_too_simple_2": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des caractères majuscules et minuscules",
- "password_too_simple_3": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des caractères majuscules, minuscules et spéciaux",
- "password_too_simple_4": "Le mot de passe doit comporter au moins 12 caractères et contenir des chiffres, des caractères majuscules, minuscules et spéciaux",
- "root_password_desynchronized": "Le mot de passe administrateur a été changé, mais YunoHost n’a pas pu le propager sur le mot de passe root !"
+ "password_too_simple_2": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules et des minuscules",
+ "password_too_simple_3": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
+ "password_too_simple_4": "Le mot de passe doit comporter au moins 12 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
+ "root_password_desynchronized": "Le mot de passe administrateur a été changé, mais YunoHost n’a pas pu le propager sur le mot de passe root !",
+ "aborting": "Interruption de la procédure.",
+ "app_not_upgraded": "Les applications suivantes n'ont pas été mises à jour : {apps}",
+ "app_start_install": "Installation de l'application {app} …",
+ "app_start_remove": "Suppression de l'application {app} …",
+ "app_start_backup": "Collecte des fichiers devant être sauvegardés pour {app} …",
+ "app_start_restore": "Restauration de l'application {app} …",
+ "app_upgrade_several_apps": "Les applications suivantes seront mises à jour : {apps}",
+ "ask_new_domain": "Nouveau domaine",
+ "ask_new_path": "Nouveau chemin",
+ "backup_actually_backuping": "Création d'une archive de sauvegarde à partir des fichiers collectés …",
+ "backup_mount_archive_for_restore": "Préparation de l'archive pour restauration …",
+ "confirm_app_install_warning": "Avertissement : cette application peut fonctionner mais n'est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l'authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L'installer quand même ? [{réponses:s}] ",
+ "confirm_app_install_danger": "AVERTISSEMENT ! Cette application est encore expérimentale (explicitement, elle ne fonctionne pas) et risque de casser votre système ! Vous ne devriez probablement PAS l'installer sans savoir ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{answers:s}] ",
+ "confirm_app_install_thirdparty": "AVERTISSEMENT ! L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l'installer si vous ne savez pas ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{réponses:s}] ",
+ "dpkg_is_broken": "Vous ne pouvez pas faire ça maintenant car dpkg/apt (le gestionnaire de paquets du système) semble avoir laissé des choses non configurées. Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a'.",
+ "dyndns_could_not_check_available": "Impossible de vérifier si {domain:s} est disponible chez {provider:s}.",
+ "file_does_not_exist": "Le fichier dont le chemin est {path:s} n'existe pas.",
+ "global_settings_setting_security_password_admin_strength": "Qualité du mot de passe administrateur",
+ "global_settings_setting_security_password_user_strength": "Qualité du mot de passe de l'utilisateur",
+ "global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Autoriser l'utilisation de la clé hôte DSA (obsolète) pour la configuration du service SSH",
+ "hook_json_return_error": "Échec de la lecture au retour du script {path:s}. Erreur : {msg:s}. Contenu brut : {raw_content}",
+ "migration_description_0007_ssh_conf_managed_by_yunohost_step1": "La configuration SSH sera gérée par YunoHost (étape 1, automatique)",
+ "migration_description_0008_ssh_conf_managed_by_yunohost_step2": "La configuration SSH sera gérée par YunoHost (étape 2, manuelle)",
+ "migration_0007_cancelled": "YunoHost n'a pas réussi à améliorer la façon dont est gérée votre configuration SSH.",
+ "migration_0007_cannot_restart": "SSH ne peut pas être redémarré après avoir essayé d'annuler la migration numéro 6.",
+ "migration_0008_general_disclaimer": "Pour améliorer la sécurité de votre serveur, il est recommandé de laisser YunoHost gérer la configuration SSH. Votre configuration SSH actuelle diffère de la configuration recommandée. Si vous laissez YunoHost la reconfigurer, la façon dont vous vous connectez à votre serveur via SSH changera comme suit :",
+ "migration_0008_port": " - vous devrez vous connecter en utilisant le port 22 au lieu de votre actuel port SSH personnalisé. N'hésitez pas à le reconfigurer ;",
+ "migration_0008_root": " - vous ne pourrez pas vous connecter en tant que root via SSH. Au lieu de cela, vous devrez utiliser l'utilisateur admin ;",
+ "migration_0008_dsa": " - la clé DSA sera désactivée. Par conséquent, il se peut que vous ayez besoin d'invalider un avertissement effrayant de votre client SSH afin de revérifier l'empreinte de votre serveur ;",
+ "migration_0008_warning": "Si vous comprenez ces avertissements et que vous acceptez de laisser YunoHost remplacer votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également passer la migration, bien que cela ne soit pas recommandé.",
+ "migration_0008_no_warning": "Aucun risque majeur n'a été identifié concernant l'écrasement de votre configuration SSH - mais nous ne pouvons pas en être absolument sûrs ;) ! Si vous acceptez de laisser YunoHost remplacer votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également passer la migration, bien que cela ne soit pas recommandé.",
+ "migrations_success": "Migration {number} {name} réussie !",
+ "pattern_password_app": "Désolé, les mots de passe ne doivent pas contenir les caractères suivants : {forbidden_chars}",
+ "root_password_replaced_by_admin_password": "Votre mot de passe root a été remplacé par votre mot de passe administrateur.",
+ "service_conf_now_managed_by_yunohost": "Le fichier de configuration '{conf}' est maintenant géré par YunoHost.",
+ "service_reload_failed": "Impossible de recharger le service '{service:s}'.\n\nJournaux récents de ce service : {logs:s}",
+ "service_reloaded": "Le service '{service:s}' a été rechargé",
+ "service_restart_failed": "Impossible de redémarrer le service '{service:s}'\n\nJournaux récents de ce service : {logs:s}",
+ "service_restarted": "Le service '{service:s}' a été redémarré",
+ "service_reload_or_restart_failed": "Impossible de recharger ou de redémarrer le service '{service:s}'\n\nJournaux récents de ce service : {logs:s}",
+ "service_reloaded_or_restarted": "Le service '{service:s}' a été rechargé ou redémarré",
+ "this_action_broke_dpkg": "Cette action a laissé des paquets non configurés par dpkg/apt (les gestionnaires de paquets système). Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a'."
}
From 3af3c2b77950b4a93c7c806d061372859674657b Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Mar 2019 19:37:52 +0100
Subject: [PATCH 132/199] Directly inject standard css + custom css and js
---
data/templates/nginx/plain/yunohost_panel.conf.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/templates/nginx/plain/yunohost_panel.conf.inc b/data/templates/nginx/plain/yunohost_panel.conf.inc
index 34afe136d..61f0af613 100644
--- a/data/templates/nginx/plain/yunohost_panel.conf.inc
+++ b/data/templates/nginx/plain/yunohost_panel.conf.inc
@@ -1,5 +1,5 @@
# Insert YunoHost panel
-sub_filter '';
+sub_filter '';
sub_filter_once on;
# Apply to other mime types than text/html
sub_filter_types application/xhtml+xml;
From b99b22bb03bc9b1cd1e53e4491af592bcf31573a Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 19 Mar 2019 01:17:45 +0100
Subject: [PATCH 133/199] Propagate file renaming for semantic
---
data/templates/nginx/plain/yunohost_panel.conf.inc | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/data/templates/nginx/plain/yunohost_panel.conf.inc b/data/templates/nginx/plain/yunohost_panel.conf.inc
index 61f0af613..d159c29f9 100644
--- a/data/templates/nginx/plain/yunohost_panel.conf.inc
+++ b/data/templates/nginx/plain/yunohost_panel.conf.inc
@@ -1,8 +1,8 @@
-# Insert YunoHost panel
-sub_filter '';
+# Insert YunoHost button + portal overlay
+sub_filter '';
sub_filter_once on;
# Apply to other mime types than text/html
sub_filter_types application/xhtml+xml;
# Prevent YunoHost panel files from being blocked by specific app rules
-location ~ ynhpanel\.(js|json|css) {
+location ~ (ynh_portal.js|ynh_overlay.css) {
}
From 390a755701e1635bc812156e1b9a687a97a0aabd Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 19 Mar 2019 13:03:22 +0100
Subject: [PATCH 134/199] Orthotypo stuff
---
locales/en.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/locales/en.json b/locales/en.json
index 9a509048e..62382cfca 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -311,7 +311,7 @@
"migration_0005_postgresql_94_not_installed": "Postgresql was not installed on your system. Nothing to do!",
"migration_0005_postgresql_96_not_installed": "Postgresql 9.4 has been found to be installed, but not postgresql 9.6!? Something weird might have happened on your system:(…",
"migration_0005_not_enough_space": "Not enough space is available in {path} to run the migration right now:(.",
- "migration_0006_disclaimer": "Yunohost now expects admin and root passwords to be synchronized. By running this migration, your root password is going to be replaced by the admin password.",
+ "migration_0006_disclaimer": "YunoHost now expects admin and root passwords to be synchronized. By running this migration, your root password is going to be replaced by the admin password.",
"migration_0007_cancelled": "YunoHost has failed to improve the way your SSH conf is managed.",
"migration_0007_cannot_restart": "SSH can't be restarted after trying to cancel migration number 6.",
"migration_0008_general_disclaimer": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH configuration differs from the recommended configuration. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change in the following way:",
From 59ff76591bc894b2f718a0ff5166aa7fc87c5b1e Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 19 Mar 2019 13:52:30 +0100
Subject: [PATCH 135/199] Typo
---
locales/en.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/locales/en.json b/locales/en.json
index 62382cfca..00fe6aa66 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -112,7 +112,7 @@
"backup_output_directory_forbidden": "Forbidden output directory. Backups can't be created in /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var or /home/yunohost.backup/archives sub-folders",
"backup_output_directory_not_empty": "The output directory is not empty",
"backup_output_directory_required": "You must provide an output directory for the backup",
- "backup_output_symlink_dir_broken": "You have a broken symlink instead of your archives directory '{path:s}'. You may have a specific setup to backup your data on an other filesystem, in this case you probably forgot to remount or plug your hard dirve or usb key.",
+ "backup_output_symlink_dir_broken": "You have a broken symlink instead of your archives directory '{path:s}'. You may have a specific setup to backup your data on an other filesystem, in this case you probably forgot to remount or plug your hard drive or usb key.",
"backup_php5_to_php7_migration_may_fail": "Could not convert your archive to support php7, your php apps may fail to restore (reason: {error:s})",
"backup_running_hooks": "Running backup hooks…",
"backup_system_part_failed": "Unable to backup the '{part:s}' system part",
From 847cecaf7fe77413af4e675a4631f1db861ceaa9 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 16:12:06 +0100
Subject: [PATCH 136/199] [fix] Fix error message for bad choice for setting
enums
---
locales/en.json | 2 +-
src/yunohost/settings.py | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/locales/en.json b/locales/en.json
index 00fe6aa66..940201ef4 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -199,7 +199,7 @@
"firewall_reloaded": "The firewall has been reloaded",
"firewall_rules_cmd_failed": "Some firewall rules commands have failed. For more information, see the log.",
"format_datetime_short": "%m/%d/%Y %I:%M %p",
- "global_settings_bad_choice_for_enum": "Bad value for setting {setting:s}, received {received_type:s}, except {expected_type:s}",
+ "global_settings_bad_choice_for_enum": "Bad choice for setting {setting:s}, received '{choice:s}' but available choices are : {available_choices:s}",
"global_settings_bad_type_for_setting": "Bad type for setting {setting:s}, received {received_type:s}, except {expected_type:s}",
"global_settings_cant_open_settings": "Failed to open settings file, reason: {reason:s}",
"global_settings_cant_serialize_settings": "Failed to serialize settings data, reason: {reason:s}",
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 81ea46114..5d2d55ede 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -109,8 +109,8 @@ def settings_set(key, value):
elif key_type == "enum":
if value not in settings[key]["choices"]:
raise YunohostError('global_settings_bad_choice_for_enum', setting=key,
- received_type=type(value).__name__,
- expected_type=", ".join(settings[key]["choices"]))
+ choice=value,
+ available_choices=", ".join(settings[key]["choices"]))
else:
raise YunohostError('global_settings_unknown_type', setting=key,
unknown_type=key_type)
From fee79820e097ebefb342bd53a16098661359b196 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 16:15:11 +0100
Subject: [PATCH 137/199] Rename nginx and ssh compatibility setting for
consistency
---
data/hooks/conf_regen/03-ssh | 4 ++--
data/hooks/conf_regen/15-nginx | 4 ++--
src/yunohost/settings.py | 8 ++++----
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh
index dbf9d69e3..0b58a461c 100755
--- a/data/hooks/conf_regen/03-ssh
+++ b/data/hooks/conf_regen/03-ssh
@@ -24,8 +24,8 @@ do_pre_regen() {
fi
# Support different strategy for security configurations
- if [[ -n "$(yunohost settings get 'service.ssh.ciphers.compatibility')" ]]; then
- ssh_ciphers_compatibility="$(yunohost settings get 'service.ssh.ciphers.compatibility')"
+ if [[ -n "$(yunohost settings get 'service.ssh.compatibility')" ]]; then
+ ssh_ciphers_compatibility="$(yunohost settings get 'service.ssh.compatibility')"
fi
export ssh_keys
diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx
index 9a7579eeb..57446c081 100755
--- a/data/hooks/conf_regen/15-nginx
+++ b/data/hooks/conf_regen/15-nginx
@@ -37,8 +37,8 @@ do_pre_regen() {
domain_list=$(sudo yunohost domain list --output-as plain --quiet)
# Support different strategy for security configurations
- if [[ -n "$(yunohost settings get 'security.ciphers.compatibility')" ]]; then
- security_ciphers_compatibility="$(yunohost settings get 'security.ciphers.compatibility')"
+ if [[ -n "$(yunohost settings get 'security.nginx.compatibility')" ]]; then
+ security_ciphers_compatibility="$(yunohost settings get 'security.nginx.compatibility')"
fi
export security_ciphers_compatibility
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 916e8b8c3..6277c8283 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -40,9 +40,9 @@ DEFAULTS = OrderedDict([
("security.password.admin.strength", {"type": "int", "default": 1}),
("security.password.user.strength", {"type": "int", "default": 1}),
("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}),
- ("service.ssh.ciphers.compatibility", {"type": "enum", "default": "modern",
+ ("security.ssh.compatibility", {"type": "enum", "default": "modern",
"choices": ["intermediate", "modern"]}),
- ("security.ciphers.compatibility", {"type": "enum", "default": "intermediate",
+ ("security.nginx.compatibility", {"type": "enum", "default": "intermediate",
"choices": ["intermediate", "modern"]}),
])
@@ -283,12 +283,12 @@ def trigger_post_change_hook(setting_name, old_value, new_value):
#
# ===========================================
-@post_change_hook("security.ciphers.compatibility")
+@post_change_hook("security.nginx.compatibility")
def reconfigure_nginx(setting_name, old_value, new_value):
if old_value != new_value:
service_regen_conf(names=['nginx'])
-@post_change_hook("service.ssh.ciphers.compatibility")
+@post_change_hook("security.ssh.compatibility")
def reconfigure_ssh(setting_name, old_value, new_value):
if old_value != new_value:
service_regen_conf(names=['ssh'])
From 2defd6ffa82368a6714b8850a1a1a960d345ac1e Mon Sep 17 00:00:00 2001
From: "ljf (zamentur)"
Date: Fri, 22 Mar 2019 16:20:35 +0100
Subject: [PATCH 138/199] [fix] Keep user info in json format
Previously it was ynhpanel.json
---
data/templates/nginx/plain/yunohost_panel.conf.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/templates/nginx/plain/yunohost_panel.conf.inc b/data/templates/nginx/plain/yunohost_panel.conf.inc
index d159c29f9..b36d79119 100644
--- a/data/templates/nginx/plain/yunohost_panel.conf.inc
+++ b/data/templates/nginx/plain/yunohost_panel.conf.inc
@@ -4,5 +4,5 @@ sub_filter_once on;
# Apply to other mime types than text/html
sub_filter_types application/xhtml+xml;
# Prevent YunoHost panel files from being blocked by specific app rules
-location ~ (ynh_portal.js|ynh_overlay.css) {
+location ~ (ynh_portal.js|ynh_overlay.css|userinfo.json) {
}
From c8d8e0e272b89e660f8f6ad860bb748642c4709a Mon Sep 17 00:00:00 2001
From: "ljf (zamentur)"
Date: Fri, 22 Mar 2019 16:30:02 +0100
Subject: [PATCH 139/199] [fix] Avoid potential conflict with some apps
---
data/templates/nginx/plain/yunohost_panel.conf.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/templates/nginx/plain/yunohost_panel.conf.inc b/data/templates/nginx/plain/yunohost_panel.conf.inc
index b36d79119..1c5a2d656 100644
--- a/data/templates/nginx/plain/yunohost_panel.conf.inc
+++ b/data/templates/nginx/plain/yunohost_panel.conf.inc
@@ -4,5 +4,5 @@ sub_filter_once on;
# Apply to other mime types than text/html
sub_filter_types application/xhtml+xml;
# Prevent YunoHost panel files from being blocked by specific app rules
-location ~ (ynh_portal.js|ynh_overlay.css|userinfo.json) {
+location ~ (ynh_portal.js|ynh_overlay.css|ynh_userinfo.json) {
}
From dcff10f6f84d03c5f15cfa29cd4698cdcb365bd3 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 16:31:45 +0100
Subject: [PATCH 140/199] Simplify setting usage in regenconf hooks
---
data/hooks/conf_regen/03-ssh | 5 +----
data/hooks/conf_regen/15-nginx | 6 +-----
data/templates/nginx/plain/yunohost_admin.conf | 2 +-
data/templates/nginx/server.tpl.conf | 2 +-
data/templates/ssh/sshd_config | 2 +-
5 files changed, 5 insertions(+), 12 deletions(-)
diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh
index 0b58a461c..265c2f746 100755
--- a/data/hooks/conf_regen/03-ssh
+++ b/data/hooks/conf_regen/03-ssh
@@ -24,13 +24,10 @@ do_pre_regen() {
fi
# Support different strategy for security configurations
- if [[ -n "$(yunohost settings get 'service.ssh.compatibility')" ]]; then
- ssh_ciphers_compatibility="$(yunohost settings get 'service.ssh.compatibility')"
- fi
+ export compatibility="$(yunohost settings get 'service.ssh.compatibility')"
export ssh_keys
export ipv6_enabled
- export ssh_ciphers_compatibility
ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config"
}
diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx
index 57446c081..60e719743 100755
--- a/data/hooks/conf_regen/15-nginx
+++ b/data/hooks/conf_regen/15-nginx
@@ -37,11 +37,7 @@ do_pre_regen() {
domain_list=$(sudo yunohost domain list --output-as plain --quiet)
# Support different strategy for security configurations
- if [[ -n "$(yunohost settings get 'security.nginx.compatibility')" ]]; then
- security_ciphers_compatibility="$(yunohost settings get 'security.nginx.compatibility')"
- fi
-
- export security_ciphers_compatibility
+ export compatibility="$(yunohost settings get 'security.nginx.compatibility')"
# add domain conf files
for domain in $domain_list; do
diff --git a/data/templates/nginx/plain/yunohost_admin.conf b/data/templates/nginx/plain/yunohost_admin.conf
index 71ad22545..c785a63c4 100644
--- a/data/templates/nginx/plain/yunohost_admin.conf
+++ b/data/templates/nginx/plain/yunohost_admin.conf
@@ -20,7 +20,7 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
- {% if security_ciphers_compatibility == "modern" %}
+ {% if compatibility == "modern" %}
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
# Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index b25e38faa..26bc78b39 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -29,7 +29,7 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
- {% if security_ciphers_compatibility == "modern" %}
+ {% if compatibility == "modern" %}
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
# The following configuration use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config
index f27ca3ebe..8dc0e8dfc 100644
--- a/data/templates/ssh/sshd_config
+++ b/data/templates/ssh/sshd_config
@@ -15,7 +15,7 @@ HostKey {{ key }}{% endfor %}
# https://infosec.mozilla.org/guidelines/openssh
# ##############################################
-{% if ssh_ciphers_compatibility == "intermediate" %}
+{% if compatibility == "intermediate" %}
KexAlgorithms diffie-hellman-group-exchange-sha256
Ciphers aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512,hmac-sha2-256
From 219dd2590c7ae876ec194fb4522e86d48a618b0a Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 17:12:38 +0100
Subject: [PATCH 141/199] Update settings descriptions
---
locales/en.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/locales/en.json b/locales/en.json
index e56b8e304..af3360b8a 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -210,12 +210,12 @@
"global_settings_setting_example_enum": "Example enum option",
"global_settings_setting_example_int": "Example int option",
"global_settings_setting_example_string": "Example string option",
- "global_settings_setting_security_ciphers_compatibility": "Admin ciphers compatibility strategy for the web",
+ "global_settings_setting_security_nginx_compatibility": "Compatibility vs. security tradeoff for the web server nginx. Affects the ciphers (and other security-related aspects)",
"global_settings_setting_security_password_admin_strength": "Admin password strength",
"global_settings_setting_security_password_user_strength": "User password strength",
+ "global_settings_setting_security_ssh_compatibility": "Compatibility vs. security tradeoff for the SSH server. Affects the ciphers (and other security-related aspects)",
"global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding it and save it in /etc/yunohost/unkown_settings.json",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration",
- "global_settings_setting_service_ssh_ciphers_compatibility": "Admin ciphers compatibility strategy for SSH",
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it's not a type supported by the system.",
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
From fefa44e0621fa6ee28515079df0755dc9e7d7e09 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 17:14:48 +0100
Subject: [PATCH 142/199] Typo in previous commits
---
data/hooks/conf_regen/03-ssh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh
index 265c2f746..54b7c55b7 100755
--- a/data/hooks/conf_regen/03-ssh
+++ b/data/hooks/conf_regen/03-ssh
@@ -24,7 +24,7 @@ do_pre_regen() {
fi
# Support different strategy for security configurations
- export compatibility="$(yunohost settings get 'service.ssh.compatibility')"
+ export compatibility="$(yunohost settings get 'security.ssh.compatibility')"
export ssh_keys
export ipv6_enabled
From 1268872ecfec60f2688f9eba2bc92a7f4d632646 Mon Sep 17 00:00:00 2001
From: Romuald
Date: Sat, 23 Mar 2019 11:58:07 +0100
Subject: [PATCH 143/199] Fix filename in error message
---
locales/en.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/locales/en.json b/locales/en.json
index 940201ef4..41c68fd16 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -212,7 +212,7 @@
"global_settings_setting_example_string": "Example string option",
"global_settings_setting_security_password_admin_strength": "Admin password strength",
"global_settings_setting_security_password_user_strength": "User password strength",
- "global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding it and save it in /etc/yunohost/unkown_settings.json",
+ "global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding it and save it in /etc/yunohost/settings-unknown.json",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration",
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it's not a type supported by the system.",
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
From a86c379233e4305cda886d89b9aa254876a44c25 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Sat, 23 Mar 2019 16:46:40 +0100
Subject: [PATCH 144/199] fix syntax in nodejs helper
---
data/helpers.d/nodejs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs
index 61a1414ef..1730990e7 100644
--- a/data/helpers.d/nodejs
+++ b/data/helpers.d/nodejs
@@ -99,7 +99,7 @@ ynh_install_nodejs () {
# Install the requested version of nodejs
uname=$(uname -m)
- if [[ $uname =~ aarch64 || $uname =~ arm64]]
+ if [[ $uname =~ aarch64 || $uname =~ arm64 ]]
then
n $nodejs_version --arch=arm64
else
From dd87b9192aefde56175f54aa5aa20cdf98baa9b8 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Sat, 23 Mar 2019 16:50:44 +0100
Subject: [PATCH 145/199] Improve naming / semantic / add comments
---
src/yunohost/domain.py | 33 +++++++++++++++++++++++++--------
1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index e604b54f0..a7141e0b8 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -408,21 +408,38 @@ def _build_dns_conf(domain, ttl=3600):
]
# Official record
- res = {
+ records = {
"basic": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in basic],
"xmpp": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in xmpp],
"mail": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in mail],
"extra": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in extra],
}
- # Custom record
- hookres = hook_callback('custom_dns_rules', args=[domain])
- for n, val in hookres.items() :
- res[n] = []
- for v in [v['stdreturn'] for p, v in val.items() if v and v['stdreturn']]:
- res[n].extend(v)
+ # Custom records
+ hook_results = hook_callback('custom_dns_rules', args=[domain])
+ for hook_name, results in hook_results.items():
+ #
+ # There can be multiple results per hook name, so results look like
+ # {'/some/path/to/hook1':
+ # { 'state': 'succeed',
+ # 'stdreturn': [{'type': 'SRV',
+ # 'name': 'stuff.foo.bar.',
+ # 'value': 'yoloswag',
+ # 'ttl': 3600}]
+ # },
+ # '/some/path/to/hook2':
+ # { ... },
+ # [...]
+ #
+ # Loop over the sub-results
+ custom_records = [v['stdreturn'] for v in results.values()
+ if v and v['stdreturn']]
- return res
+ records[hook_name] = []
+ for record_list in custom_records:
+ records[hook_name].extend(record_list)
+
+ return records
def _get_DKIM(domain):
From cd9fcd265d99e52d4da02f5546483d802c074c98 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Sat, 23 Mar 2019 16:54:47 +0100
Subject: [PATCH 146/199] fix conflict
---
data/helpers.d/nodejs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs
index 1730990e7..098ed4410 100644
--- a/data/helpers.d/nodejs
+++ b/data/helpers.d/nodejs
@@ -99,7 +99,7 @@ ynh_install_nodejs () {
# Install the requested version of nodejs
uname=$(uname -m)
- if [[ $uname =~ aarch64 || $uname =~ arm64 ]]
+ if [[ $uname =~ aarch64 || $uname =~ arm64 ]]
then
n $nodejs_version --arch=arm64
else
From 5ac5cc93107efea4a5855afb686d4f4640d244bf Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Sat, 23 Mar 2019 17:31:56 +0100
Subject: [PATCH 147/199] Check format of data retrieved from hook stdreturn
---
src/yunohost/domain.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index a7141e0b8..70a4ef5c9 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -437,6 +437,15 @@ def _build_dns_conf(domain, ttl=3600):
records[hook_name] = []
for record_list in custom_records:
+ # Check that record_list is indeed a list of dict
+ # with the required keys
+ if not isinstance(record_list, list) \
+ or any(not isinstance(record, dict) for record in record_list) \
+ or any(key not in record for record in record_list for key in ["name", "ttl", "type", "value"]):
+ # Display an error, mainly for app packagers trying to implement a hook
+ logger.warning("Ignored custom record from hook '%s' because the data is not a *list* of dict with keys name, ttl, type and value. Raw data : %s" % (hook_name, record_list))
+ continue
+
records[hook_name].extend(record_list)
return records
From fad3edf66a21ef56b43b5e314745b167bb683175 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 25 Mar 2019 16:50:49 +0100
Subject: [PATCH 148/199] [fix] SSH login breaks if password is longer than 127
chars...
---
locales/en.json | 1 +
src/yunohost/tools.py | 5 +++++
2 files changed, 6 insertions(+)
diff --git a/locales/en.json b/locales/en.json
index 18ab84be1..694df0707 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -4,6 +4,7 @@
"admin_password": "Administration password",
"admin_password_change_failed": "Unable to change password",
"admin_password_changed": "The administration password has been changed",
+ "admin_password_too_long": "Please choose a password shorter than 127 characters",
"app_already_installed": "{app:s} is already installed",
"app_already_installed_cant_change_url": "This app is already installed. The url cannot be changed just by this function. Look into `app changeurl` if it's available.",
"app_already_up_to_date": "{app:s} is already up to date",
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index a011b1546..42114c7e9 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -132,6 +132,11 @@ def tools_adminpw(auth, new_password, check_strength=True):
if check_strength:
assert_password_is_strong_enough("admin", new_password)
+ # UNIX seems to not like password longer than 127 chars ...
+ # e.g. SSH login gets broken (or even 'su admin' when entering the password)
+ if len(new_password) >= 127:
+ raise YunohostError('admin_password_too_long')
+
new_hash = _hash_user_password(new_password)
try:
From 84c66990c34d3bb28c3eef819fbfcd2bd470e44c Mon Sep 17 00:00:00 2001
From: Gabriel Corona
Date: Sat, 16 Mar 2019 23:04:33 +0100
Subject: [PATCH 149/199] Avoid having to shell-escape arguments in
ynh_handle_getopts_args
Fixes $ ` and \ injections.
---
data/helpers.d/getopts | 22 ++--------------------
1 file changed, 2 insertions(+), 20 deletions(-)
diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts
index 694543e1d..894c9395f 100644
--- a/data/helpers.d/getopts
+++ b/data/helpers.d/getopts
@@ -152,19 +152,8 @@ ynh_handle_getopts_args () {
# If there's already another value for this option, add a ; before adding the new value
eval ${option_var}+="\;"
fi
- # Escape double quote to prevent any interpretation during the eval
- all_args[$i]="${all_args[$i]//\"/\\\"}"
- # Escape $ as well to prevent the string following it to be seen as a variable.
- all_args[$i]="${all_args[$i]//$/\\\$}"
- # For the record.
- # We're using eval here to get the content of the variable stored itself as simple text in $option_var...
- # Other ways to get that content would be to use either ${!option_var} or declare -g ${option_var}
- # But... ${!option_var} can't be used as left part of an assignation.
- # declare -g ${option_var} will create a local variable (despite -g !) and will not be available for the helper itself.
- # So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one!
-
- eval ${option_var}+=\"${all_args[$i]}\"
+ eval ${option_var}+='"${all_args[$i]}"'
shift_value=$(( shift_value + 1 ))
fi
done
@@ -202,14 +191,7 @@ ynh_handle_getopts_args () {
# The variable name will be stored in 'option_var'
local option_var="${args_array[$option_flag]%=}"
- # Escape double quote to prevent any interpretation during the eval
- arguments[$i]="${arguments[$i]//\"/\\\"}"
- # Escape $ as well to prevent the string following it to be seen as a variable.
- arguments[$i]="${arguments[$i]//$/\\\$}"
-
- # Store each value given as argument in the corresponding variable
- # The values will be stored in the same order than $args_array
- eval ${option_var}+=\"${arguments[$i]}\"
+ eval ${option_var}+='"${arguments[$i]}"'
done
unset legacy_args
else
From 2f0dd973b8686de62f92b1aefa91a6d68ebb6100 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 01:14:45 +0100
Subject: [PATCH 150/199] Rework system-part of tools_update...
---
src/yunohost/tools.py | 51 ++++++++++++++++++++++++++++++++++---------
1 file changed, 41 insertions(+), 10 deletions(-)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index 42114c7e9..92c68eca9 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -41,7 +41,7 @@ from moulinette import msettings, msignals, m18n
from moulinette.core import init_authenticator
from yunohost.utils.error import YunohostError
from moulinette.utils.log import getActionLogger
-from moulinette.utils.process import check_output
+from moulinette.utils.process import check_output, call_async_output
from moulinette.utils.filesystem import read_json, write_to_json
from yunohost.app import app_fetchlist, app_info, app_upgrade, app_ssowatconf, app_list, _install_appslist_fetch_cron
from yunohost.domain import domain_add, domain_list, _get_maindomain, _set_maindomain
@@ -474,23 +474,54 @@ def tools_update(ignore_apps=False, ignore_packages=False):
# "packages" will list upgradable packages
packages = []
if not ignore_packages:
- cache = apt.Cache()
# Update APT cache
+ # LC_ALL=C is here to make sure the results are in english
+ command = "LC_ALL=C apt update"
+ # TODO : add @is_unit_operation to tools_update so that the
+ # debug output can be fetched when there's an issue...
+ callbacks = (
+ # stdout goes to debug
+ lambda l: logger.debug(l.rstrip()),
+ # stderr goes to warning
+ # FIXME : filter the damn "CLI interface not stable" from apt >.>
+ lambda l: logger.warning(l.rstrip()),
+ )
+
logger.info(m18n.n('updating_apt_cache'))
- if not cache.update():
+
+ returncode = call_async_output(command, callbacks, shell=True)
+
+ if returncode != 0:
+
+ # TODO : here, we should run something like a
+ # `cat /etc/apt/sources.list /etc/apt/sources.list.d/*`
+ # and append it to the error message to improve debugging
+
raise YunohostError('update_cache_failed')
- cache.open(None)
- cache.upgrade(True)
+ # List upgradable packages
+ # LC_ALL=C is here to make sure the results are in english
+ upgradable_raw = check_output("LC_ALL=C apt list --upgradable")
- # Add changelogs to the result
- for pkg in cache.get_changes():
+ # Dirty parsing of the output
+ upgradable_raw = [l.strip() for l in upgradable_raw.split("\n") if l.strip()]
+ for line in upgradable_raw:
+ # Remove stupid warning and verbose messages >.>
+ if "apt does not have a stable CLI interface" in line or "Listing..." in line:
+ continue
+ # line should look like :
+ # yunohost/stable 3.5.0.2+201903211853 all [upgradable from: 3.4.2.4+201903080053]
+ line = line.split()
+ if len(line) != 6:
+ logger.warning("Failed to parse this line : %s" % ' '.join(line))
+ continue
packages.append({
- 'name': pkg.name,
- 'fullname': pkg.fullname,
- 'changelog': pkg.get_changelog()
+ "name": line[0].split("/")[0],
+ "new_version": line[1],
+ "current_version": line[5].strip("]"),
})
+
logger.debug(m18n.n('done'))
# "apps" will list upgradable packages
From 2f034bb7c9b6d62943a9ea1897b3000b5c33f193 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 04:01:08 +0100
Subject: [PATCH 151/199] Factorize function to list upgradable packages
---
src/yunohost/tools.py | 50 ++++++++++++++++++++++++-------------------
1 file changed, 28 insertions(+), 22 deletions(-)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index 92c68eca9..154ad086a 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -500,28 +500,7 @@ def tools_update(ignore_apps=False, ignore_packages=False):
raise YunohostError('update_cache_failed')
- # List upgradable packages
- # LC_ALL=C is here to make sure the results are in english
- upgradable_raw = check_output("LC_ALL=C apt list --upgradable")
-
- # Dirty parsing of the output
- upgradable_raw = [l.strip() for l in upgradable_raw.split("\n") if l.strip()]
- for line in upgradable_raw:
- # Remove stupid warning and verbose messages >.>
- if "apt does not have a stable CLI interface" in line or "Listing..." in line:
- continue
- # line should look like :
- # yunohost/stable 3.5.0.2+201903211853 all [upgradable from: 3.4.2.4+201903080053]
- line = line.split()
- if len(line) != 6:
- logger.warning("Failed to parse this line : %s" % ' '.join(line))
- continue
- packages.append({
- "name": line[0].split("/")[0],
- "new_version": line[1],
- "current_version": line[5].strip("]"),
- })
-
+ packages = list(_list_upgradable_apt_packages())
logger.debug(m18n.n('done'))
# "apps" will list upgradable packages
@@ -550,6 +529,33 @@ def tools_update(ignore_apps=False, ignore_packages=False):
return {'packages': packages, 'apps': apps}
+# TODO : move this to utils/packages.py ?
+def _list_upgradable_apt_packages():
+
+ # List upgradable packages
+ # LC_ALL=C is here to make sure the results are in english
+ upgradable_raw = check_output("LC_ALL=C apt list --upgradable")
+
+ # Dirty parsing of the output
+ upgradable_raw = [l.strip() for l in upgradable_raw.split("\n") if l.strip()]
+ for line in upgradable_raw:
+ # Remove stupid warning and verbose messages >.>
+ if "apt does not have a stable CLI interface" in line or "Listing..." in line:
+ continue
+ # line should look like :
+ # yunohost/stable 3.5.0.2+201903211853 all [upgradable from: 3.4.2.4+201903080053]
+ line = line.split()
+ if len(line) != 6:
+ logger.warning("Failed to parse this line : %s" % ' '.join(line))
+ continue
+
+ yield {
+ "name": line[0].split("/")[0],
+ "new_version": line[1],
+ "current_version": line[5].strip("]"),
+ }
+
+
@is_unit_operation()
def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=False):
"""
From e298838949ce3b2ab924a303dff3cbeffc9b39f3 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 26 Mar 2019 19:45:16 +0100
Subject: [PATCH 152/199] Filter boring apt warnings + report an error if there
was real warnings
---
locales/en.json | 1 +
src/yunohost/tools.py | 17 ++++++++++++++---
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/locales/en.json b/locales/en.json
index 694df0707..da27c7cb0 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -483,6 +483,7 @@
"unlimit": "No quota",
"unrestore_app": "App '{app:s}' will not be restored",
"update_cache_failed": "Unable to update APT cache",
+ "update_cache_warning": "Some errors happened while updating APT cache",
"updating_apt_cache": "Fetching available upgrades for system packages…",
"upgrade_complete": "Upgrade complete",
"upgrading_packages": "Upgrading packages…",
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index 154ad086a..f9d86ad09 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -480,12 +480,21 @@ def tools_update(ignore_apps=False, ignore_packages=False):
command = "LC_ALL=C apt update"
# TODO : add @is_unit_operation to tools_update so that the
# debug output can be fetched when there's an issue...
+
+ # Filter boring message about "apt not having a stable CLI interface"
+ # Also keep track of wether or not we encountered a warning...
+ warnings = []
+ def is_legit_warning(m):
+ legit_warning = m.rstrip() and "apt does not have a stable CLI interface" not in m.rstrip()
+ if legit_warning:
+ warnings.append(m)
+ return legit_warning
+
callbacks = (
# stdout goes to debug
lambda l: logger.debug(l.rstrip()),
- # stderr goes to warning
- # FIXME : filter the damn "CLI interface not stable" from apt >.>
- lambda l: logger.warning(l.rstrip()),
+ # stderr goes to warning except for the boring apt messages
+ lambda l: logger.warning(l.rstrip()) if is_legit_warning(l) else logger.debug(l.rstrip())
)
logger.info(m18n.n('updating_apt_cache'))
@@ -499,6 +508,8 @@ def tools_update(ignore_apps=False, ignore_packages=False):
# and append it to the error message to improve debugging
raise YunohostError('update_cache_failed')
+ elif warnings:
+ logger.error(m18n.n('update_cache_warning'))
packages = list(_list_upgradable_apt_packages())
logger.debug(m18n.n('done'))
From 0bd781be4735169685473f7e3969c6a45f6c0b3e Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 27 Mar 2019 15:11:11 +0100
Subject: [PATCH 153/199] [fix] Small issue with optional arguments... c.f.
issue 1261
---
src/yunohost/app.py | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index f21352fc2..8f2de0caa 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -2257,13 +2257,17 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
elif arg_default is not None:
arg_value = arg_default
- # Validate argument value
- if (arg_value is None or arg_value == '') \
- and not arg.get('optional', False):
- raise YunohostError('app_argument_required', name=arg_name)
- elif arg_value is None:
- args_dict[arg_name] = ''
- continue
+ # If the value is empty (none or '')
+ # then check if arg is optional or not
+ if arg_value is None or arg_value == '':
+ if arg.get("optional", False):
+ # Argument is optional, keep an empty value
+ # and that's all for this arg !
+ args_dict[arg_name] = ''
+ continue
+ else:
+ # The argument is required !
+ raise YunohostError('app_argument_required', name=arg_name)
# Validate argument choice
if arg_choices and arg_value not in arg_choices:
From 162eeb7e06e04ec32ed66331a184c9527fa68e82 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 27 Mar 2019 18:08:46 +0100
Subject: [PATCH 154/199] Dump sources list in error message to help debugging
---
locales/en.json | 4 ++--
src/yunohost/tools.py | 21 ++++++++++++++-------
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/locales/en.json b/locales/en.json
index da27c7cb0..64f2e6766 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -482,8 +482,8 @@
"unit_unknown": "Unknown unit '{unit:s}'",
"unlimit": "No quota",
"unrestore_app": "App '{app:s}' will not be restored",
- "update_cache_failed": "Unable to update APT cache",
- "update_cache_warning": "Some errors happened while updating APT cache",
+ "update_apt_cache_failed": "Unable to update the cache of APT (Debian's package manager). Here is a dump of the sources.list lines which might help to identify problematic lines : \n{sourceslist}",
+ "update_apt_cache_warning": "Some errors happened while updating the cache of APT (Debian's package manager). Here is a dump of the sources.list lines which might help to identify problematic lines : \n{sourceslist}",
"updating_apt_cache": "Fetching available upgrades for system packages…",
"upgrade_complete": "Upgrade complete",
"upgrading_packages": "Upgrading packages…",
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index f9d86ad09..635399801 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -30,6 +30,7 @@ import json
import subprocess
import pwd
import socket
+from glob import glob
from xmlrpclib import Fault
from importlib import import_module
from collections import OrderedDict
@@ -502,14 +503,9 @@ def tools_update(ignore_apps=False, ignore_packages=False):
returncode = call_async_output(command, callbacks, shell=True)
if returncode != 0:
-
- # TODO : here, we should run something like a
- # `cat /etc/apt/sources.list /etc/apt/sources.list.d/*`
- # and append it to the error message to improve debugging
-
- raise YunohostError('update_cache_failed')
+ raise YunohostError('update_apt_cache_failed', sourceslist='\n'.join(_dump_sources_list()))
elif warnings:
- logger.error(m18n.n('update_cache_warning'))
+ logger.error(m18n.n('update_apt_cache_warning', sourceslist='\n'.join(_dump_sources_list())))
packages = list(_list_upgradable_apt_packages())
logger.debug(m18n.n('done'))
@@ -567,6 +563,17 @@ def _list_upgradable_apt_packages():
}
+def _dump_sources_list():
+
+ filenames = glob("/etc/apt/sources.list") + glob("/etc/apt/sources.list.d/*")
+ for filename in filenames:
+ with open(filename, "r") as f:
+ for line in f.readlines():
+ if line.startswith("#") or not line.strip():
+ continue
+ yield filename.replace("/etc/apt/", "") + ":" + line.strip()
+
+
@is_unit_operation()
def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=False):
"""
From 8b8df94befe8906e0a05b6fc3afb23ac796b90c2 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Thu, 28 Mar 2019 19:37:23 +0100
Subject: [PATCH 155/199] Keep useful comments...
We still use eval, comment about its usage is still relevant...
---
data/helpers.d/getopts | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts
index 894c9395f..b6cd95f3c 100644
--- a/data/helpers.d/getopts
+++ b/data/helpers.d/getopts
@@ -153,6 +153,13 @@ ynh_handle_getopts_args () {
eval ${option_var}+="\;"
fi
+ # For the record.
+ # We're using eval here to get the content of the variable stored itself as simple text in $option_var...
+ # Other ways to get that content would be to use either ${!option_var} or declare -g ${option_var}
+ # But... ${!option_var} can't be used as left part of an assignation.
+ # declare -g ${option_var} will create a local variable (despite -g !) and will not be available for the helper itself.
+ # So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one!
+
eval ${option_var}+='"${all_args[$i]}"'
shift_value=$(( shift_value + 1 ))
fi
@@ -191,6 +198,8 @@ ynh_handle_getopts_args () {
# The variable name will be stored in 'option_var'
local option_var="${args_array[$option_flag]%=}"
+ # Store each value given as argument in the corresponding variable
+ # The values will be stored in the same order than $args_array
eval ${option_var}+='"${arguments[$i]}"'
done
unset legacy_args
From 0a3f12ed58d37e5722311041d8e696ebd6f52150 Mon Sep 17 00:00:00 2001
From: Laurent Peuch
Date: Sun, 31 Mar 2019 04:10:23 +0200
Subject: [PATCH 156/199] [mod] use ask key for display_text instead and
support i18n
---
src/yunohost/app.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index 8561e2667..70d21afb1 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -2204,7 +2204,7 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
# do not print for webadmin
if arg_type == 'display_text' and msettings.get('interface') != 'api':
- print(arg["text"])
+ print(_value_for_locale(arg['ask']))
continue
# Attempt to retrieve argument value
From 26e77b77ffe08f1c5a03eb22e9ad2f3ca0167cee Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Mon, 1 Apr 2019 21:24:15 +0200
Subject: [PATCH 157/199] Force stdout to stderr in ynh_debug
Merge as a micro decision.
---
data/helpers.d/debug | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/data/helpers.d/debug b/data/helpers.d/debug
index ea20ffc1a..7ad097dbd 100644
--- a/data/helpers.d/debug
+++ b/data/helpers.d/debug
@@ -37,6 +37,8 @@ ynh_debug () {
PS4='$(basename ${BASH_SOURCE[0]})-L${LINENO}: '
# Force xtrace to stderr
BASH_XTRACEFD=2
+ # Force stdout to stderr
+ exec 1>&2
fi
if [ "$trace" == "0" ]
then
@@ -44,6 +46,8 @@ ynh_debug () {
set +x
# Put xtrace back to its original fild descriptor
BASH_XTRACEFD=$old_bash_xtracefd
+ # Restore stdout
+ exec 1>&1
fi
# Renable set xtrace
set -x
From 0c67559c43ba50a5d069888b1a5ea00fd3f7f21c Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Tue, 2 Apr 2019 12:33:49 +0200
Subject: [PATCH 158/199] Fix missing legacy_args
Merged as a micro decision
---
data/helpers.d/print | 1 +
1 file changed, 1 insertion(+)
diff --git a/data/helpers.d/print b/data/helpers.d/print
index 95d2af139..f1120367a 100644
--- a/data/helpers.d/print
+++ b/data/helpers.d/print
@@ -201,6 +201,7 @@ previous_weight=0
base_time=$(date +%s)
ynh_script_progression () {
# Declare an array to define the options of this helper.
+ local legacy_args=mwtl
declare -Ar args_array=( [m]=message= [w]=weight= [t]=time [l]=last )
local message
local weight
From 92b5777aff64c8e7c914dea4bd050bceb6aeb32a Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Tue, 2 Apr 2019 12:36:17 +0200
Subject: [PATCH 159/199] Fix missing legacy_args
Merged as a micro decision
---
data/helpers.d/system | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index c4c049c31..a491b19b5 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -75,6 +75,7 @@ ynh_get_debian_release () {
# | arg: -e, --length= - Length of the error log : Default : 20
ynh_systemd_action() {
# Declare an array to define the options of this helper.
+ local legacy_args=nalpte
declare -Ar args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= )
local service_name
local action
@@ -175,6 +176,7 @@ ynh_clean_check_starting () {
# Requires YunoHost version 3.?.? or higher.
ynh_read_manifest () {
# Declare an array to define the options of this helper.
+ local legacy_args=mk
declare -Ar args_array=( [m]=manifest= [k]=manifest_key= )
local manifest
local manifest_key
@@ -200,6 +202,8 @@ ynh_read_manifest () {
#
# Requires YunoHost version 3.?.? or higher.
ynh_app_upstream_version () {
+ # Declare an array to define the options of this helper.
+ local legacy_args=m
declare -Ar args_array=( [m]=manifest= )
local manifest
# Manage arguments with getopts
@@ -221,6 +225,8 @@ ynh_app_upstream_version () {
#
# Requires YunoHost version 3.?.? or higher.
ynh_app_package_version () {
+ # Declare an array to define the options of this helper.
+ local legacy_args=m
declare -Ar args_array=( [m]=manifest= )
local manifest
# Manage arguments with getopts
From 9766a73e0d0fb39172984419f516bca417cb2d7d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A9lanie=20Chauvel?=
Date: Mon, 18 Mar 2019 18:24:46 +0000
Subject: [PATCH 160/199] Translated using Weblate (French)
Currently translated at 99.4% (501 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
---
locales/fr.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/locales/fr.json b/locales/fr.json
index b864c5ac7..6a41ff45b 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -471,7 +471,7 @@
"service_description_php7.0-fpm": "exécute des applications écrites en PHP avec nginx",
"users_available": "Liste des utilisateurs disponibles :",
"good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase de chiffrement) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
- "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères - bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou d'utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
+ "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères — bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou d'utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
"migration_0006_disclaimer": "Yunohost s’attend maintenant à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
"migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.",
From 92a097ea50209b0af41fb39bb03f655d57784d4b Mon Sep 17 00:00:00 2001
From: ppr
Date: Tue, 19 Mar 2019 07:52:39 +0000
Subject: [PATCH 161/199] Translated using Weblate (French)
Currently translated at 99.4% (501 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
---
locales/fr.json | 58 ++++++++++++++++++++++++-------------------------
1 file changed, 29 insertions(+), 29 deletions(-)
diff --git a/locales/fr.json b/locales/fr.json
index 6a41ff45b..bea929837 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -1,13 +1,13 @@
{
- "action_invalid": "Action « {action:s} » incorrecte",
+ "action_invalid": "Action '{action:s}' incorrecte",
"admin_password": "Mot de passe d’administration",
"admin_password_change_failed": "Impossible de changer le mot de passe",
"admin_password_changed": "Le mot de passe d’administration a été modifié",
"app_already_installed": "{app:s} est déjà installé",
- "app_argument_choice_invalid": "Choix invalide pour le paramètre « {name:s} », il doit être l’un de {choices:s}",
- "app_argument_invalid": "Valeur invalide pour le paramètre `{name:s}` : {error:s}",
+ "app_argument_choice_invalid": "Choix invalide pour le paramètre '{name:s}', il doit être l’un de {choices:s}",
+ "app_argument_invalid": "Valeur invalide pour le paramètre '{name:s}' : {error:s}",
"app_argument_missing": "Paramètre manquant « {:s} »",
- "app_argument_required": "Le paramètre `{name:s}` est requis",
+ "app_argument_required": "Le paramètre '{name:s}' est requis",
"app_extraction_failed": "Impossible d’extraire les fichiers d’installation",
"app_id_invalid": "Identifiant d’application invalide",
"app_incompatible": "L’application {app} est incompatible avec votre version de YunoHost",
@@ -35,7 +35,7 @@
"appslist_retrieve_error": "Impossible de récupérer la liste d’applications distante {appslist:s} : {error:s}",
"appslist_unknown": "La liste d’applications {appslist:s} est inconnue.",
"ask_current_admin_password": "Mot de passe d’administration actuel",
- "ask_email": "Adresse courriel",
+ "ask_email": "Adresse de courriel",
"ask_firstname": "Prénom",
"ask_lastname": "Nom",
"ask_list_to_remove": "Liste à supprimer",
@@ -43,7 +43,7 @@
"ask_new_admin_password": "Nouveau mot de passe d’administration",
"ask_password": "Mot de passe",
"backup_action_required": "Vous devez préciser ce qui est à sauvegarder",
- "backup_app_failed": "Impossible de sauvegarder l’application « {app:s} »",
+ "backup_app_failed": "Impossible de sauvegarder l’application '{app:s}'",
"backup_archive_app_not_found": "L’application '{app:s}' n’a pas été trouvée dans l’archive de la sauvegarde",
"backup_archive_hook_not_exec": "Le script « {hook:s} » n'a pas été exécuté dans cette sauvegarde",
"backup_archive_name_exists": "Une archive de sauvegarde avec ce nom existe déjà",
@@ -60,8 +60,8 @@
"backup_invalid_archive": "Archive de sauvegarde invalide",
"backup_nothings_done": "Il n’y a rien à sauvegarder",
"backup_output_directory_forbidden": "Dossier de destination interdit. Les sauvegardes ne peuvent être créées dans les sous-dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives",
- "backup_output_directory_not_empty": "Le dossier de sortie n’est pas vide",
- "backup_output_directory_required": "Vous devez spécifier un dossier de sortie pour la sauvegarde",
+ "backup_output_directory_not_empty": "Le répertoire de destination n'est pas vide",
+ "backup_output_directory_required": "Vous devez spécifier un dossier de destination pour la sauvegarde",
"backup_running_app_script": "Lancement du script de sauvegarde de l’application « {app:s} »...",
"backup_running_hooks": "Exécution des scripts de sauvegarde …",
"custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application personnalisée {app:s}",
@@ -255,7 +255,7 @@
"certmanager_certificate_fetching_or_enabling_failed": "Il semble que l’activation du nouveau certificat pour {domain:s} a échoué …",
"certmanager_attempt_to_renew_nonLE_cert": "Le certificat pour le domaine {domain:s} n’est pas émis par Let’s Encrypt. Impossible de le renouveler automatiquement !",
"certmanager_attempt_to_renew_valid_cert": "Le certificat pour le domaine {domain:s} est sur le point d’expirer ! Utilisez --force pour contourner cela",
- "certmanager_domain_http_not_working": "Il semble que le domaine {domain:s} n’est pas accessible via HTTP. Veuillez vérifier que vos configuration DNS et Nginx sont correctes",
+ "certmanager_domain_http_not_working": "Il semble que le domaine {domain:s} ne soit pas accessible via HTTP. Veuillez vérifier que vos configuration DNS et Nginx sont correctes",
"certmanager_error_no_A_record": "Aucun enregistrement DNS 'A' n’a été trouvé pour {domain:s}. Vous devez faire pointer votre nom de domaine vers votre machine pour être en mesure d’installer un certificat Let’s Encrypt ! (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
"certmanager_domain_dns_ip_differs_from_public_ip": "L’enregistrement DNS 'A' du domaine {domain:s} est différent de l’adresse IP de ce serveur. Si vous avez récemment modifié votre enregistrement 'A', veuillez attendre sa propagation (quelques vérificateur de propagation DNS sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
"certmanager_cannot_read_cert": "Quelque chose s’est mal passé lors de la tentative d’ouverture du certificat actuel pour le domaine {domain:s} (fichier : {file:s}), la cause est : {reason:s}",
@@ -264,13 +264,13 @@
"certmanager_cert_renew_success": "Renouvellement avec succès d’un certificat Let’s Encrypt pour le domaine {domain:s} !",
"certmanager_old_letsencrypt_app_detected": "\nYunoHost a détecté que l’application « letsencrypt » est installé, ce qui est en conflit avec les nouvelles fonctionnalités de gestion intégrée de certificats dans YunoHost. Si vous souhaitez utiliser ces nouvelles fonctionnalités intégrées, veuillez lancer les commandes suivantes pour migrer votre installation :\n\n yunohost app remove letsencrypt\n yunohost domain cert-install\n\nN.B. : cela tentera de réinstaller les certificats de tous les domaines avec un certificat Let's Encrypt ou ceux auto-signés",
"certmanager_cert_signing_failed": "La signature du nouveau certificat a échoué",
- "certmanager_no_cert_file": "Impossible de lire le fichier de certificat pour le domaine {domain:s} (fichier : {file:s})",
+ "certmanager_no_cert_file": "Impossible de lire le fichier de/du certificat pour le domaine {domain:s} (fichier : {file:s})",
"certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration Nginx {filepath:s} est en conflit et doit être préalablement retiré",
"certmanager_hit_rate_limit": "Trop de certificats ont déjà été émis récemment pour ce même ensemble de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails sur les ratios et limitations",
"ldap_init_failed_to_create_admin": "L’initialisation de LDAP n’a pas réussi à créer l’utilisateur admin",
"ssowat_persistent_conf_read_error": "Erreur lors de la lecture de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
"ssowat_persistent_conf_write_error": "Erreur lors de la sauvegarde de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
- "domain_cannot_remove_main": "Impossible de supprimer le domaine principal. Commencez par définir un nouveau domaine principal",
+ "domain_cannot_remove_main": "Impossible de supprimer le domaine principal. Définissez d'abord un nouveau domaine principal",
"certmanager_self_ca_conf_file_not_found": "Le fichier de configuration pour l’autorité du certificat auto-signé est introuvable (fichier : {file:s})",
"certmanager_unable_to_parse_self_CA_name": "Impossible d’analyser le nom de l’autorité du certificat auto-signé (fichier : {file:s})",
"mailbox_used_space_dovecot_down": "Le service mail Dovecot doit être démarré, si vous souhaitez voir l’espace disque occupé par la messagerie",
@@ -279,7 +279,7 @@
"certmanager_acme_not_configured_for_domain": "Le certificat du domaine {domain:s} ne semble pas être correctement installé. Veuillez d'abord exécuter cert-install.",
"certmanager_domain_not_resolved_locally": "Le domaine {domain:s} ne peut être résolu depuis votre serveur YunoHost. Cela peut se produire si vous avez récemment modifié votre enregistrement DNS. Si c'est le cas, merci d’attendre quelques heures qu’il se propage. Si le problème persiste, envisager d’ajouter {domain:s} au fichier /etc/hosts. (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces vérifications.)",
"certmanager_http_check_timeout": "Expiration du délai lorsque le serveur a essayé de se contacter lui-même via HTTP en utilisant l'adresse IP public {ip:s} du domaine {domain:s}. Vous rencontrez peut-être un problème d’hairpinning ou alors le pare-feu/routeur en amont de votre serveur est mal configuré.",
- "certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Let’s Encrypt. L’installation ou le renouvellement du certificat a été annulé - veuillez réessayer plus tard.",
+ "certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Let’s Encrypt. L’installation ou le renouvellement du certificat a été annulé. Veuillez réessayer plus tard.",
"appslist_retrieve_bad_format": "Le fichier récupéré pour la liste d’applications {appslist:s} n’est pas valide",
"domain_hostname_failed": "Échec de la création d’un nouveau nom d’hôte",
"yunohost_ca_creation_success": "L’autorité de certification locale a été créée.",
@@ -288,39 +288,39 @@
"appslist_migrating": "Migration de la liste d’applications {appslist:s} …",
"appslist_could_not_migrate": "Impossible de migrer la liste {appslist:s} ! Impossible d’exploiter l’URL. L’ancienne tâche programmée a été conservée dans {bkp_file:s}.",
"appslist_corrupted_json": "Impossible de charger la liste d’applications. Il semble que {filename:s} soit corrompu.",
- "app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Regardez avec `app changeurl` si c’est disponible.",
+ "app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Regardez si cela est disponible avec `app changeurl`.",
"app_change_no_change_url_script": "L’application {app_name:s} ne prend pas encore en charge le changement d’URL, vous pourriez avoir besoin de la mettre à jour.",
- "app_change_url_failed_nginx_reload": "Le redémarrage de nginx a échoué. Voici la sortie de `nginx -t` :\n{nginx_errors:s}",
- "app_change_url_identical_domains": "L’ancien et le nouveau couple domaine/chemin_de_l'URL sont identiques pour (`{domain:s}{path:s}`), rien à faire.",
- "app_change_url_no_script": "L’application `{app_name:s}` ne prend pas encore en charge le changement d’URL. Vous devriez peut-être la mettre à jour.",
+ "app_change_url_failed_nginx_reload": "Le redémarrage de Nginx a échoué. Voici la sortie de 'nginx -t' :\n{nginx_errors:s}",
+ "app_change_url_identical_domains": "L’ancien et le nouveau couple domaine/chemin_de_l'URL sont identiques pour ('{domain:s}{path:s}'), rien à faire.",
+ "app_change_url_no_script": "L’application '{app_name:s}' ne prend pas encore en charge le changement d’URL. Vous devriez peut-être la mettre à jour.",
"app_change_url_success": "L’URL de l’application {app:s} a été changée en {domain:s}{path:s}",
- "app_location_unavailable": "Cette URL n’est pas disponible ou est en conflit avec une application existante\n{apps:s}",
+ "app_location_unavailable": "Cette URL n’est pas disponible ou est en conflit avec une application existante :\n{apps:s}",
"app_already_up_to_date": "{app:s} est déjà à jour",
"invalid_url_format": "Format d’URL non valide",
- "global_settings_bad_choice_for_enum": "La valeur du paramètre {setting:s} est incorrecte. Reçu : {received_type:s} mais attendu : {expected_type:s}",
- "global_settings_bad_type_for_setting": "Le type du paramètre {setting:s} est incorrect. Reçu : {received_type:s} mais attendu : {expected_type:s}",
+ "global_settings_bad_choice_for_enum": "La valeur du paramètre {setting:s} est incorrecte. Reçu {received_type:s} alors que {expected_type:s} était attendu",
+ "global_settings_bad_type_for_setting": "Le type du paramètre {setting:s} est incorrect. Reçu {received_type:s} alors que {expected_type:s} était attendu",
"global_settings_cant_open_settings": "Échec de l’ouverture du ficher de configurations car : {reason:s}",
"global_settings_cant_serialize_setings": "Échec de sérialisation des données de configurations, cause : {reason:s}",
"global_settings_cant_write_settings": "Échec d’écriture du fichier de configurations car : {reason:s}",
"global_settings_key_doesnt_exists": "La clef '{settings_key:s}' n’existe pas dans les configurations générales, vous pouvez voir toutes les clefs disponibles en saisissant 'yunohost settings list'",
- "global_settings_reset_success": "Réussite ! Vos configurations précédentes ont été sauvegardées dans {path:s}",
+ "global_settings_reset_success": "Super ! Vos configurations précédentes ont été sauvegardées dans {path:s}",
"global_settings_setting_example_bool": "Exemple d’option booléenne",
"global_settings_setting_example_int": "Exemple d’option de type entier",
"global_settings_setting_example_string": "Exemple d’option de type chaîne",
"global_settings_setting_example_enum": "Exemple d’option de type énumération",
- "global_settings_unknown_type": "Situation inattendue, la configuration {setting:s} semble avoir le type {unknown_type:s} mais celui-ci n'est pas pris en charge par le système.",
+ "global_settings_unknown_type": "Situation inattendue : la configuration {setting:s} semble avoir le type {unknown_type:s} mais celui-ci n'est pas pris en charge par le système.",
"global_settings_unknown_setting_from_settings_file": "Clef inconnue dans les paramètres : '{setting_key:s}', rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
"service_conf_file_kept_back": "Le fichier de configuration « {conf} » devrait être supprimé par le service {service} mais a été conservé.",
"backup_abstract_method": "Cette méthode de sauvegarde n’a pas encore été implémentée",
"backup_applying_method_tar": "Création de l’archive tar de la sauvegarde …",
"backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder …",
- "backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans de référentiel borg-backup …",
+ "backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans le référentiel/répertoire borg-backup …",
"backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée '{method:s}' …",
"backup_archive_system_part_not_available": "La partie '{part:s}' du système n’est pas disponible dans cette sauvegarde",
"backup_archive_mount_failed": "Le montage de l’archive de sauvegarde a échoué",
"backup_archive_writing_error": "Impossible d'ajouter des fichiers '{source:s}' (nommés dans l'archive : '{dest:s}') à sauvegarder dans l'archive compressée '{archive:s}'",
- "backup_ask_for_copying_if_needed": "Certains fichiers n’ont pas pu être préparés pour être sauvegardés en utilisant la méthode qui évite temporairement de gaspiller de l’espace sur le système. Pour mener la sauvegarde, {size:s} Mo doivent être temporairement utilisés. Acceptez-vous ?",
+ "backup_ask_for_copying_if_needed": "Certains fichiers n’ont pas pu être préparés pour être sauvegardés en utilisant la méthode qui évite temporairement de gaspiller de l’espace sur le système. Pour réaliser la sauvegarde, {size:s} Mo doivent être temporairement utilisés. Acceptez-vous ?",
"backup_borg_not_implemented": "La méthode de sauvegarde Borg n’est pas encore implémentée",
"backup_cant_mount_uncompress_archive": "Impossible de monter en lecture seule le dossier de l’archive décompressée",
"backup_copying_to_organize_the_archive": "Copie de {size:s} Mo pour organiser l’archive",
@@ -346,8 +346,8 @@
"restore_not_enough_disk_space": "Espace disponible insuffisant (libre : {free_space:d} octets, nécessaire : {needed_space:d} octets, marge de sécurité : {margin:d} octets)",
"restore_system_part_failed": "Impossible de restaurer la partie « {part:s} » du système",
"backup_couldnt_bind": "Impossible de lier {src:s} avec {dest:s}.",
- "domain_dns_conf_is_just_a_recommendation": "Cette page montre la configuration *recommandée*. Elle ne configure *pas* le DNS pour vous. Il est de votre responsabilité que de configurer votre zone DNS chez votre registrar DNS avec cette recommandation.",
- "domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost, soit YunoHost n’est pas correctement connecté à internet ou alors le serveur de dynette est arrêté. Erreur : {error}",
+ "domain_dns_conf_is_just_a_recommendation": "Cette page montre la configuration *recommandée*. Elle ne configure *pas* le DNS pour vous. Il est de votre responsabilité que de configurer votre zone DNS chez votre fournisseur/registrar DNS avec cette recommandation.",
+ "domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost. Soit YunoHost n’est pas correctement connecté à internet, soit le serveur de dynette est en panne ou ne répond pas. Erreur : {error}",
"migrations_backward": "Migration en arrière.",
"migrations_bad_value_for_target": "Nombre invalide pour le paramètre « target », les numéros de migration sont ou {}",
"migrations_cant_reach_migration_file": "Impossible d’accéder aux fichiers de migrations avec le chemin %s",
@@ -368,7 +368,7 @@
"ask_path": "Chemin",
"dyndns_could_not_check_provide": "Impossible de vérifier si {provider:s} peut fournir {domain:s}.",
"dyndns_domain_not_provided": "Le fournisseur DynDNS {provider:s} ne peut pas fournir le domaine {domain:s}.",
- "app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine {domain} car déjà utilisé par l'application '{other_app}'",
+ "app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine {domain} car il est déjà utilisé par l'application '{other_app}'",
"app_upgrade_app_name": "Mise à jour de l’application {app} …",
"backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives '{path:s}'. Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas, vous avez probablement oublié de monter ou de connecter votre disque dur ou votre clef USB.",
"migrate_tsig_end": "La migration à hmac-sha512 est terminée",
@@ -470,7 +470,7 @@
"recommend_to_add_first_user": "La post-installation est terminée, mais YunoHost a besoin d’au moins un utilisateur pour fonctionner correctement. Vous devez en ajouter un en utilisant « yunohost user create » ou l’interface d’administration.",
"service_description_php7.0-fpm": "exécute des applications écrites en PHP avec nginx",
"users_available": "Liste des utilisateurs disponibles :",
- "good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase de chiffrement) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
+ "good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères — bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou d'utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
"migration_0006_disclaimer": "Yunohost s’attend maintenant à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
@@ -492,9 +492,9 @@
"ask_new_path": "Nouveau chemin",
"backup_actually_backuping": "Création d'une archive de sauvegarde à partir des fichiers collectés …",
"backup_mount_archive_for_restore": "Préparation de l'archive pour restauration …",
- "confirm_app_install_warning": "Avertissement : cette application peut fonctionner mais n'est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l'authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L'installer quand même ? [{réponses:s}] ",
+ "confirm_app_install_warning": "Avertissement : cette application peut fonctionner mais n'est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l'authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L'installer quand même ? [{answers:s}] ",
"confirm_app_install_danger": "AVERTISSEMENT ! Cette application est encore expérimentale (explicitement, elle ne fonctionne pas) et risque de casser votre système ! Vous ne devriez probablement PAS l'installer sans savoir ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{answers:s}] ",
- "confirm_app_install_thirdparty": "AVERTISSEMENT ! L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l'installer si vous ne savez pas ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{réponses:s}] ",
+ "confirm_app_install_thirdparty": "AVERTISSEMENT ! L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l'installer si vous ne savez pas ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{answers:s}] ",
"dpkg_is_broken": "Vous ne pouvez pas faire ça maintenant car dpkg/apt (le gestionnaire de paquets du système) semble avoir laissé des choses non configurées. Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a'.",
"dyndns_could_not_check_available": "Impossible de vérifier si {domain:s} est disponible chez {provider:s}.",
"file_does_not_exist": "Le fichier dont le chemin est {path:s} n'existe pas.",
From 63912c25f4ef986a8cb634cc050f7774fac93e31 Mon Sep 17 00:00:00 2001
From: xaloc33
Date: Sun, 17 Mar 2019 16:20:39 +0000
Subject: [PATCH 162/199] Translated using Weblate (Catalan)
Currently translated at 22.6% (114 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ca/
---
locales/ca.json | 48 ++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 40 insertions(+), 8 deletions(-)
diff --git a/locales/ca.json b/locales/ca.json
index bfad4d2bd..44d473d91 100644
--- a/locales/ca.json
+++ b/locales/ca.json
@@ -29,20 +29,20 @@
"app_not_properly_removed": "{app:s} no s'ha pogut suprimir correctament",
"app_package_need_update": "El paquet de l'aplicació {app} ha de ser actualitzat per poder seguir els canvis de YunoHost",
"app_removed": "{app:s} ha estat suprimida",
- "app_requirements_checking": "Verificació dels paquets requerits per {app}",
+ "app_requirements_checking": "Verificació dels paquets requerits per {app}…",
"app_requirements_failed": "No es poden satisfer els requeriments per {app}: {error}",
"app_requirements_unmeet": "No es compleixen els requeriments per {app}, el paquet {pkgname} ({version}) ha de ser {spec}",
"app_sources_fetch_failed": "No s'han pogut carregar els fitxers font",
"app_unknown": "Aplicació desconeguda",
"app_unsupported_remote_type": "El tipus remot utilitzat per l'aplicació no està suportat",
- "app_upgrade_app_name": "Actualitzant l'aplicació {app}...",
+ "app_upgrade_app_name": "Actualitzant l'aplicació {app}…",
"app_upgrade_failed": "No s'ha pogut actualitzar {app:s}",
"app_upgrade_some_app_failed": "No s'han pogut actualitzar algunes aplicacions",
"app_upgraded": "{app:s} ha estat actualitzada",
"appslist_corrupted_json": "No s'han pogut carregar les llistes d'aplicacions. Sembla que {filename:s} està danyat.",
"appslist_could_not_migrate": "No s'ha pogut migrar la llista d'aplicacions {appslist:s}! No s'ha pogut analitzar la URL... L'antic cronjob s'ha guardat a {bkp_file:s}.",
"appslist_fetched": "S'ha descarregat la llista d'aplicacions {appslist:s} correctament",
- "appslist_migrating": "Migrant la llista d'aplicacions {appslist:s} ...",
+ "appslist_migrating": "Migrant la llista d'aplicacions {appslist:s}…",
"appslist_name_already_tracked": "Ja hi ha una llista d'aplicacions registrada amb el nom {name:s}.",
"appslist_removed": "S'ha eliminat la llista d'aplicacions {appslist:s}",
"appslist_retrieve_bad_format": "L'arxiu obtingut per la llista d'aplicacions {appslist:s} no és vàlid",
@@ -61,10 +61,10 @@
"backup_abstract_method": "Encara no s'ha implementat aquest mètode de copia de seguretat",
"backup_action_required": "S'ha d'especificar què s'ha de guardar",
"backup_app_failed": "No s'ha pogut fer la còpia de seguretat de l'aplicació \"{app:s}\"",
- "backup_applying_method_borg": "Enviant tots els fitxers de la còpia de seguretat al repositori borg-backup...",
- "backup_applying_method_copy": "Còpia de tots els fitxers a la còpia de seguretat...",
- "backup_applying_method_custom": "Crida del mètode de còpia de seguretat personalitzat \"{method:s}\"...",
- "backup_applying_method_tar": "Creació de l'arxiu tar de la còpia de seguretat...",
+ "backup_applying_method_borg": "Enviant tots els fitxers de la còpia de seguretat al repositori borg-backup…",
+ "backup_applying_method_copy": "Còpia de tots els fitxers a la còpia de seguretat…",
+ "backup_applying_method_custom": "Crida del mètode de còpia de seguretat personalitzat \"{method:s}\"…",
+ "backup_applying_method_tar": "Creació de l'arxiu tar de la còpia de seguretat…",
"backup_archive_app_not_found": "L'aplicació \"{app:s}\" no es troba dins l'arxiu de la còpia de seguretat",
"backup_archive_broken_link": "No s'ha pogut accedir a l'arxiu de la còpia de seguretat (enllaç invàlid cap a {path:s})",
"backup_archive_mount_failed": "No s'ha pogut carregar l'arxiu de la còpia de seguretat",
@@ -80,5 +80,37 @@
"backup_copying_to_organize_the_archive": "Copiant {size:s}MB per organitzar l'arxiu",
"backup_couldnt_bind": "No es pot lligar {src:s} amb {dest:s}.",
"backup_created": "S'ha creat la còpia de seguretat",
- "backup_creating_archive": "Creant l'arxiu de la còpia de seguretat"
+ "backup_creating_archive": "Creant l'arxiu de la còpia de seguretat…",
+ "aborting": "Avortant.",
+ "app_not_upgraded": "Les següents aplicacions no s'han actualitzat: {apps}",
+ "app_start_install": "instal·lant l'aplicació {app}…",
+ "app_start_remove": "Eliminant l'aplicació {app}…",
+ "app_start_backup": "Recuperant els fitxers pels que s'ha de fer una còpia de seguretat per {app}…",
+ "app_start_restore": "Recuperant l'aplicació {app}…",
+ "app_upgrade_several_apps": "S'actualitzaran les següents aplicacions: {apps}",
+ "ask_new_domain": "Nou domini",
+ "ask_new_path": "Nou camí",
+ "backup_actually_backuping": "S'està creant un arxiu de còpia de seguretat a partir dels fitxers recuperats…",
+ "backup_creation_failed": "Ha fallat la creació de la còpia de seguretat",
+ "backup_csv_addition_failed": "No s'han pogut afegir fitxers per a fer-ne la còpia de seguretat al fitxer CSV",
+ "backup_csv_creation_failed": "No s'ha pogut crear el fitxer CSV necessari per a futures operacions de recuperació",
+ "backup_custom_backup_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"backup\"",
+ "backup_custom_mount_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"mount\"",
+ "backup_custom_need_mount_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"need_mount\"",
+ "backup_delete_error": "No s'ha pogut suprimir \"{path:s}\"",
+ "backup_deleted": "S'ha suprimit la còpia de seguretat",
+ "backup_extracting_archive": "Extraient l'arxiu de la còpia de seguretat…",
+ "backup_hook_unknown": "Script de còpia de seguretat \"{hook:s}\" desconegut",
+ "backup_invalid_archive": "Arxiu de còpia de seguretat no vàlid",
+ "backup_method_borg_finished": "La còpia de seguretat a borg ha acabat",
+ "backup_method_copy_finished": "La còpia de la còpia de seguretat ha acabat",
+ "backup_method_custom_finished": "El mètode de còpia de seguretat personalitzat \"{method:s}\" ha acabat",
+ "backup_method_tar_finished": "S'ha creat l'arxiu de còpia de seguretat tar",
+ "backup_mount_archive_for_restore": "Preparant l'arxiu per la restauració…",
+ "good_practices_about_user_password": "Esteu a punt de definir una nova contrasenya d'usuari. La contrasenya ha de tenir un mínim de 8 caràcters ; tot i que és de bona pràctica utilitzar una contrasenya més llarga (és a dir una frase de contrasenya) i/o utilitzar diferents tipus de caràcters (majúscules, minúscules, dígits i caràcters especials).",
+ "password_listed": "Aquesta contrasenya és una de les més utilitzades en el món. Si us plau utilitzeu-ne una més única.",
+ "password_too_simple_1": "La contrasenya ha de tenir un mínim de 8 caràcters",
+ "password_too_simple_2": "La contrasenya ha de tenir un mínim de 8 caràcters i ha de contenir dígits, majúscules i minúscules",
+ "password_too_simple_3": "La contrasenya ha de tenir un mínim de 8 caràcters i tenir dígits, majúscules, minúscules i caràcters especials",
+ "password_too_simple_4": "La contrasenya ha de tenir un mínim de 12 caràcters i tenir dígits, majúscules, minúscules i caràcters especials"
}
From 6523caffcbd473350c133d2e115adadf70920055 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A9lanie=20Chauvel?=
Date: Mon, 18 Mar 2019 20:09:52 +0000
Subject: [PATCH 163/199] Translated using Weblate (Esperanto)
Currently translated at 6.7% (34 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eo/
---
locales/eo.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/locales/eo.json b/locales/eo.json
index 6a7a82784..b9d973557 100644
--- a/locales/eo.json
+++ b/locales/eo.json
@@ -16,7 +16,7 @@
"yunohost_already_installed": "YunoHost estas jam instalita",
"yunohost_ca_creation_failed": "Ne eblas krei atestan aŭtoritaton",
"yunohost_ca_creation_success": "Loka atesta aŭtoritato estas kreita.",
- "yunohost_installing": "Instalata YunoHost...",
+ "yunohost_installing": "Instalante YunoHost…",
"service_description_glances": "monitoras sisteminformojn de via servilo",
"service_description_metronome": "mastrumas XMPP tujmesaĝilon kontojn",
"service_description_mysql": "stokas aplikaĵojn datojn (SQL datumbazo)",
From a4f00f2eff9de781d64e496d748d26dfbf67af3f Mon Sep 17 00:00:00 2001
From: ppr
Date: Tue, 19 Mar 2019 09:06:19 +0000
Subject: [PATCH 164/199] Translated using Weblate (French)
Currently translated at 97.4% (491 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
---
locales/fr.json | 234 ++++++++++++++++++++++++------------------------
1 file changed, 117 insertions(+), 117 deletions(-)
diff --git a/locales/fr.json b/locales/fr.json
index bea929837..58c25d3ad 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -111,7 +111,7 @@
"hook_choice_invalid": "Choix incorrect : '{:s}'",
"hook_exec_failed": "Échec de l’exécution du script : {path:s}",
"hook_exec_not_terminated": "L’exécution du script {path:s} ne s’est pas terminée correctement",
- "hook_list_by_invalid": "La propriété de tri des actions est invalide",
+ "hook_list_by_invalid": "Propriété invalide pour lister les actions par",
"hook_name_unknown": "Nom de l'action '{name:s}' inconnu",
"installation_complete": "Installation terminée",
"installation_failed": "Échec de l’installation",
@@ -119,8 +119,8 @@
"iptables_unavailable": "Vous ne pouvez pas jouer avec iptables ici. Vous êtes soit dans un conteneur, soit votre noyau ne le prend pas en charge",
"ldap_initialized": "L’annuaire LDAP a été initialisé",
"license_undefined": "indéfinie",
- "mail_alias_remove_failed": "Impossible de supprimer l’alias courriel '{mail:s}'",
- "mail_domain_unknown": "Le domaine '{domain:s}' du courriel est inconnu",
+ "mail_alias_remove_failed": "Impossible de supprimer l’alias de courriel '{mail:s}'",
+ "mail_domain_unknown": "Le domaine '{domain:s}' est inconnu pour cette adresse de courriel",
"mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert '{mail:s}'",
"maindomain_change_failed": "Impossible de modifier le domaine principal",
"maindomain_changed": "Le domaine principal a été modifié",
@@ -136,119 +136,119 @@
"mysql_db_creation_failed": "Impossible de créer la base de données MySQL",
"mysql_db_init_failed": "Impossible d’initialiser la base de données MySQL",
"mysql_db_initialized": "La base de données MySQL a été initialisée",
- "network_check_mx_ko": "L’enregistrement DNS MX n’est pas précisé",
+ "network_check_mx_ko": "L’enregistrement DNS MX n’est pas défini",
"network_check_smtp_ko": "Le trafic courriel sortant (port 25 SMTP) semble bloqué par votre réseau",
"network_check_smtp_ok": "Le trafic courriel sortant (port 25 SMTP) n’est pas bloqué",
"new_domain_required": "Vous devez spécifier le nouveau domaine principal",
"no_appslist_found": "Aucune liste d’applications n’a été trouvée",
"no_internet_connection": "Le serveur n’est pas connecté à Internet",
"no_ipv6_connectivity": "La connectivité IPv6 n’est pas disponible",
- "no_restore_script": "Le script de sauvegarde n’a pas été trouvé pour l’application « {app:s} »",
+ "no_restore_script": "Le script de sauvegarde n’a pas été trouvé pour l’application '{app:s}'",
"no_such_conf_file": "Le fichier {file:s} n’existe pas, il ne peut pas être copié",
- "not_enough_disk_space": "L’espace disque est insuffisant sur « {path:s} »",
- "package_not_installed": "Le paquet « {pkgname} » n’est pas installé",
- "package_unexpected_error": "Une erreur inattendue est survenue avec le paquet « {pkgname} »",
- "package_unknown": "Paquet « {pkgname} » inconnu",
+ "not_enough_disk_space": "L’espace disque est insuffisant sur '{path:s}'",
+ "package_not_installed": "Le paquet '{pkgname}' n’est pas installé",
+ "package_unexpected_error": "Une erreur inattendue s'est produite lors du traitement du paquet '{pkgname}'",
+ "package_unknown": "Le paquet '{pkgname}' est inconnu",
"packages_no_upgrade": "Il n’y a aucun paquet à mettre à jour",
"packages_upgrade_critical_later": "Les paquets critiques ({packages:s}) seront mis à jour ultérieurement",
"packages_upgrade_failed": "Impossible de mettre à jour tous les paquets",
"path_removal_failed": "Impossible de supprimer le chemin {:s}",
- "pattern_backup_archive_name": "Doit être un nom de fichier valide avec un maximum de 30 caractères, et composé uniquement de caractères alphanumériques et de tirets tels que - et _",
- "pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.org)",
- "pattern_email": "Doit être une adresse courriel valide (ex. : pseudo@domain.org)",
+ "pattern_backup_archive_name": "Doit être un nom de fichier valide avec un maximum de 30 caractères, et composé uniquement de caractères alphanumériques et de tirets tels que -_.",
+ "pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.fr)",
+ "pattern_email": "Doit être une adresse de courriel valide (ex. : pseudo@domaine.fr)",
"pattern_firstname": "Doit être un prénom valide",
"pattern_lastname": "Doit être un nom valide",
- "pattern_listname": "Doit être composé uniquement de caractères alphanumériques et de tirets bas",
- "pattern_mailbox_quota": "Doit être une taille avec le suffixe b/k/M/G/T ou 0 pour désactiver le quota",
+ "pattern_listname": "Doit être composé uniquement de caractères alphanumériques et de tirets bas (aussi appelé tiret du 8 ou underscore)",
+ "pattern_mailbox_quota": "Doit avoir une taille suffixée avec b/k/M/G/T ou 0 pour désactiver le quota",
"pattern_password": "Doit être composé d’au moins 3 caractères",
- "pattern_port": "Doit être un numéro de port valide (ex. : 0-65535)",
- "pattern_port_or_range": "Doit être un numéro de port valide (ex. : 0-65535) ou une gamme de ports (ex. : 100:200)",
+ "pattern_port": "Doit être un numéro de port valide compris entre 0 et 65535",
+ "pattern_port_or_range": "Doit être un numéro de port valide compris entre 0 et 65535, ou une gamme de ports (exemple : 100:200)",
"pattern_positive_number": "Doit être un nombre positif",
- "pattern_username": "Doit être composé uniquement de caractères alphanumériques minuscules et de tirets bas",
+ "pattern_username": "Doit être composé uniquement de caractères alphanumériques minuscules et de tirets bas (aussi appelé tiret du 8 ou underscore)",
"port_already_closed": "Le port {port:d} est déjà fermé pour les connexions {ip_version:s}",
"port_already_opened": "Le port {port:d} est déjà ouvert pour les connexions {ip_version:s}",
"port_available": "Le port {port:d} est disponible",
"port_unavailable": "Le port {port:d} n’est pas disponible",
"restore_action_required": "Vous devez préciser ce qui est à restaurer",
- "restore_already_installed_app": "Une application est déjà installée avec l’id « {app:s} »",
- "restore_app_failed": "Impossible de restaurer l’application « {app:s} »",
+ "restore_already_installed_app": "Une application est déjà installée avec l’identifiant '{app:s}'",
+ "restore_app_failed": "Impossible de restaurer l’application '{app:s}'",
"restore_cleaning_failed": "Impossible de nettoyer le dossier temporaire de restauration",
"restore_complete": "Restauration terminée",
"restore_confirm_yunohost_installed": "Voulez-vous vraiment restaurer un système déjà installé ? [{answers:s}]",
"restore_failed": "Impossible de restaurer le système",
- "restore_hook_unavailable": "Le script de restauration « {part:s} » n’est pas disponible sur votre système, et n’est pas non plus dans l’archive",
+ "restore_hook_unavailable": "Le script de restauration '{part:s}' n’est pas disponible sur votre système, et ne l'est pas non plus dans l’archive",
"restore_nothings_done": "Rien n’a été restauré",
"restore_running_app_script": "Exécution du script de restauration de l'application '{app:s}' .…",
"restore_running_hooks": "Exécution des scripts de restauration …",
"service_add_configuration": "Ajout du fichier de configuration {file:s}",
- "service_add_failed": "Impossible d’ajouter le service « {service:s} »",
- "service_added": "Le service « {service:s} » a été ajouté",
- "service_already_started": "Le service « {service:s} » est déjà démarré",
- "service_already_stopped": "Le service « {service:s} » est déjà arrêté",
- "service_cmd_exec_failed": "Impossible d’exécuter la commande « {command:s} »",
- "service_conf_file_backed_up": "Le fichier de configuration « {conf} » a été sauvegardé dans « {backup} »",
- "service_conf_file_copy_failed": "Impossible de copier le nouveau fichier de configuration « {new} » vers « {conf} »",
- "service_conf_file_manually_modified": "Le fichier de configuration « {conf} » a été modifié manuellement et ne sera pas mis à jour",
- "service_conf_file_manually_removed": "Le fichier de configuration « {conf} » a été supprimé manuellement et ne sera pas créé",
+ "service_add_failed": "Impossible d’ajouter le service '{service:s}'",
+ "service_added": "Le service '{service:s}' a été ajouté",
+ "service_already_started": "Le service '{service:s}' est déjà démarré",
+ "service_already_stopped": "Le service '{service:s}' est déjà arrêté",
+ "service_cmd_exec_failed": "Impossible d’exécuter la commande '{command:s}'",
+ "service_conf_file_backed_up": "Le fichier de configuration '{conf}' a été sauvegardé dans '{backup}'",
+ "service_conf_file_copy_failed": "Impossible de copier le nouveau fichier de configuration '{new}' vers '{conf}'",
+ "service_conf_file_manually_modified": "Le fichier de configuration '{conf}' a été modifié manuellement et ne sera pas mis à jour",
+ "service_conf_file_manually_removed": "Le fichier de configuration '{conf}' a été supprimé manuellement et ne sera pas créé",
"service_conf_file_not_managed": "Le fichier de configuration « {conf} » n'est pas géré pour l'instant et ne sera pas mis à jour",
- "service_conf_file_remove_failed": "Impossible de supprimer le fichier de configuration « {conf} »",
- "service_conf_file_removed": "Le fichier de configuration « {conf} » a été supprimé",
- "service_conf_file_updated": "Le fichier de configuration « {conf} » a été mis à jour",
- "service_conf_up_to_date": "La configuration du service « {service} » est déjà à jour",
- "service_conf_updated": "La configuration a été mise à jour pour le service « {service} »",
- "service_conf_would_be_updated": "La configuration du service « {service} » aurait été mise à jour",
+ "service_conf_file_remove_failed": "Impossible de supprimer le fichier de configuration '{conf}'",
+ "service_conf_file_removed": "Le fichier de configuration '{conf}' a été supprimé",
+ "service_conf_file_updated": "Le fichier de configuration '{conf}' a été mis à jour",
+ "service_conf_up_to_date": "La configuration du service '{service}' est déjà à jour",
+ "service_conf_updated": "La configuration a été mise à jour pour le service '{service}'",
+ "service_conf_would_be_updated": "La configuration du service '{service}' aurait été mise à jour",
"service_configuration_conflict": "Le fichier {file:s} a été modifié depuis sa dernière génération. Veuillez y appliquer les modifications manuellement ou utiliser l’option --force (ce qui écrasera toutes les modifications effectuées sur le fichier).",
"service_configured": "La configuration du service « {service:s} » a été générée avec succès",
"service_configured_all": "La configuration de tous les services a été générée avec succès",
- "service_disable_failed": "Impossible de désactiver le service « {service:s} »\n\nJournaux récents : {logs:s}",
- "service_disabled": "Le service « {service:s} » a été désactivé",
- "service_enable_failed": "Impossible d’activer le service « {service:s} »\n\nJournaux récents : {logs:s}",
- "service_enabled": "Le service « {service:s} » a été activé",
- "service_no_log": "Aucun journal à afficher pour le service « {service:s} »",
- "service_regenconf_dry_pending_applying": "Vérification des configurations en attentes qui pourraient être appliquées pour le service « {service} »…",
+ "service_disable_failed": "Impossible de désactiver le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
+ "service_disabled": "Le service '{service:s}' a été désactivé",
+ "service_enable_failed": "Impossible d’activer le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
+ "service_enabled": "Le service '{service:s}' a été activé",
+ "service_no_log": "Aucun journal historisé à afficher pour le service '{service:s}'",
+ "service_regenconf_dry_pending_applying": "Vérification des configurations en attentes qui pourraient être appliquées au le service '{service}' …",
"service_regenconf_failed": "Impossible de régénérer la configuration pour les services : {services}",
- "service_regenconf_pending_applying": "Application des configurations en attentes pour le service « {service} »…",
- "service_remove_failed": "Impossible d’enlever le service « {service:s} »",
- "service_removed": "Le service « {service:s} » a été enlevé",
- "service_start_failed": "Impossible de démarrer le service « {service:s} »\n\nJournaux récents : {logs:s}",
- "service_started": "Le service « {service:s} » a été démarré",
- "service_status_failed": "Impossible de déterminer le statut du service « {service:s} »",
- "service_stop_failed": "Impossible d’arrêter le service « {service:s} »\n\nJournaux récents : {logs:s}",
- "service_stopped": "Le service « {service:s} » a été arrêté",
- "service_unknown": "Service « {service:s} » inconnu",
+ "service_regenconf_pending_applying": "Application des configurations en attentes pour le service '{service}' …",
+ "service_remove_failed": "Impossible de supprimer le service '{service:s}'",
+ "service_removed": "Le service '{service:s}' a été supprimé",
+ "service_start_failed": "Impossible de démarrer le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
+ "service_started": "Le service '{service:s}' a été démarré",
+ "service_status_failed": "Impossible de déterminer le statut du service '{service:s}'",
+ "service_stop_failed": "Impossible d’arrêter le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
+ "service_stopped": "Le service '{service:s}' a été arrêté",
+ "service_unknown": "Le service '{service:s}' est inconnu",
"services_configured": "La configuration a été générée avec succès",
"show_diff": "Voici les différences :\n{diff:s}",
"ssowat_conf_generated": "La configuration de SSOwat a été générée",
"ssowat_conf_updated": "La configuration de SSOwat a été mise à jour",
"system_upgraded": "Le système a été mis à jour",
- "system_username_exists": "Le nom d’utilisateur existe déjà dans les utilisateurs système",
- "unbackup_app": "L’application « {app:s} » ne sera pas sauvegardée",
- "unexpected_error": "Une erreur inattendue est survenue",
- "unit_unknown": "Unité « {unit:s} » inconnue",
+ "system_username_exists": "Ce nom d’utilisateur existe déjà dans les utilisateurs système",
+ "unbackup_app": "L’application '{app:s}' ne sera pas sauvegardée",
+ "unexpected_error": "Une erreur inattendue est survenue : {error}",
+ "unit_unknown": "L'unité '{unit:s}' est inconnue",
"unlimit": "Pas de quota",
- "unrestore_app": "L’application « {app:s} » ne sera pas restaurée",
- "update_cache_failed": "Impossible de mettre à jour le cache de l’APT",
- "updating_apt_cache": "Récupération des mises à jour disponibles pour les paquets du système .…",
+ "unrestore_app": "L’application '{app:s}' ne sera pas restaurée",
+ "update_cache_failed": "Impossible de mettre à jour le cache de l'outil de gestion avancée des paquets (APT)",
+ "updating_apt_cache": "Récupération des mises à jour disponibles pour les paquets du système …",
"upgrade_complete": "Mise à jour terminée",
"upgrading_packages": "Mise à jour des paquets en cours …",
"upnp_dev_not_found": "Aucun périphérique compatible UPnP n’a été trouvé",
"upnp_disabled": "UPnP a été désactivé",
"upnp_enabled": "UPnP a été activé",
- "upnp_port_open_failed": "Impossible d’ouvrir les ports avec UPnP",
+ "upnp_port_open_failed": "Impossible d’ouvrir les ports UPnP",
"user_created": "L’utilisateur a été créé",
"user_creation_failed": "Impossible de créer l’utilisateur",
"user_deleted": "L’utilisateur a été supprimé",
"user_deletion_failed": "Impossible de supprimer l’utilisateur",
"user_home_creation_failed": "Impossible de créer le dossier personnel de l’utilisateur",
"user_info_failed": "Impossible de récupérer les informations de l’utilisateur",
- "user_unknown": "Utilisateur « {user:s} » inconnu",
+ "user_unknown": "L'utilisateur {user:s} est inconnu",
"user_update_failed": "Impossible de modifier l’utilisateur",
"user_updated": "L’utilisateur a été modifié",
"yunohost_already_installed": "YunoHost est déjà installé",
"yunohost_ca_creation_failed": "Impossible de créer l’autorité de certification",
"yunohost_configured": "YunoHost a été configuré",
- "yunohost_installing": "Installation de YunoHost en cours …",
- "yunohost_not_installed": "YunoHost n’est pas ou pas correctement installé. Veuillez exécuter « yunohost tools postinstall »",
+ "yunohost_installing": "L'installation de YunoHost est en cours …",
+ "yunohost_not_installed": "YunoHost n’est pas ou pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'",
"certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de vouloir remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner cela)",
"certmanager_domain_unknown": "Domaine {domain:s} inconnu",
"certmanager_domain_cert_not_selfsigned": "Le certificat du domaine {domain:s} n’est pas auto-signé. Voulez-vous vraiment le remplacer ? (Utilisez --force pour cela)",
@@ -267,13 +267,13 @@
"certmanager_no_cert_file": "Impossible de lire le fichier de/du certificat pour le domaine {domain:s} (fichier : {file:s})",
"certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration Nginx {filepath:s} est en conflit et doit être préalablement retiré",
"certmanager_hit_rate_limit": "Trop de certificats ont déjà été émis récemment pour ce même ensemble de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails sur les ratios et limitations",
- "ldap_init_failed_to_create_admin": "L’initialisation de LDAP n’a pas réussi à créer l’utilisateur admin",
+ "ldap_init_failed_to_create_admin": "L’initialisation de l'annuaire LDAP n’a pas réussi à créer l’utilisateur admin",
"ssowat_persistent_conf_read_error": "Erreur lors de la lecture de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
"ssowat_persistent_conf_write_error": "Erreur lors de la sauvegarde de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
"domain_cannot_remove_main": "Impossible de supprimer le domaine principal. Définissez d'abord un nouveau domaine principal",
"certmanager_self_ca_conf_file_not_found": "Le fichier de configuration pour l’autorité du certificat auto-signé est introuvable (fichier : {file:s})",
"certmanager_unable_to_parse_self_CA_name": "Impossible d’analyser le nom de l’autorité du certificat auto-signé (fichier : {file:s})",
- "mailbox_used_space_dovecot_down": "Le service mail Dovecot doit être démarré, si vous souhaitez voir l’espace disque occupé par la messagerie",
+ "mailbox_used_space_dovecot_down": "Le service de courriel Dovecot doit être démarré, si vous souhaitez voir l’espace disque occupé par la messagerie",
"domains_available": "Domaines disponibles :",
"backup_archive_broken_link": "Impossible d’accéder à l’archive de sauvegarde (lien invalide vers {path:s})",
"certmanager_acme_not_configured_for_domain": "Le certificat du domaine {domain:s} ne semble pas être correctement installé. Veuillez d'abord exécuter cert-install.",
@@ -311,7 +311,7 @@
"global_settings_unknown_type": "Situation inattendue : la configuration {setting:s} semble avoir le type {unknown_type:s} mais celui-ci n'est pas pris en charge par le système.",
"global_settings_unknown_setting_from_settings_file": "Clef inconnue dans les paramètres : '{setting_key:s}', rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
- "service_conf_file_kept_back": "Le fichier de configuration « {conf} » devrait être supprimé par le service {service} mais a été conservé.",
+ "service_conf_file_kept_back": "Le fichier de configuration '{conf}' devait être supprimé par le service {service} mais a été conservé.",
"backup_abstract_method": "Cette méthode de sauvegarde n’a pas encore été implémentée",
"backup_applying_method_tar": "Création de l’archive tar de la sauvegarde …",
"backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder …",
@@ -340,28 +340,28 @@
"backup_with_no_restore_script_for_app": "L’application {app:s} n’a pas de script de restauration, vous ne pourrez pas restaurer automatiquement la sauvegarde de cette application.",
"global_settings_cant_serialize_settings": "Échec de la sérialisation des données de paramétrage car : {reason:s}",
"restore_removing_tmp_dir_failed": "Impossible de sauvegarder un ancien dossier temporaire",
- "restore_extracting": "Extraction des fichiers nécessaires depuis l’archive…",
- "restore_mounting_archive": "Montage de l’archive dans « {path:s} »",
- "restore_may_be_not_enough_disk_space": "Votre système semble ne pas avoir suffisamment d’espace disponible (libre : {free_space:d} octets, nécessaire : {needed_space:d} octets, marge de sécurité : {margin:d} octets)",
- "restore_not_enough_disk_space": "Espace disponible insuffisant (libre : {free_space:d} octets, nécessaire : {needed_space:d} octets, marge de sécurité : {margin:d} octets)",
- "restore_system_part_failed": "Impossible de restaurer la partie « {part:s} » du système",
+ "restore_extracting": "Extraction des fichiers nécessaires depuis l’archive …",
+ "restore_mounting_archive": "Montage de l’archive dans '{path:s}'",
+ "restore_may_be_not_enough_disk_space": "Votre système semble ne pas avoir suffisamment d’espace disponible (L'espace libre est de {free_space:d} octets. Le besoin d'espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d'espace nécessaire est de {margin:d} octets)",
+ "restore_not_enough_disk_space": "Espace disponible insuffisant (L'espace libre est de {free_space:d} octets. Le besoin d'espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d'espace nécessaire est de {margin:d} octets)",
+ "restore_system_part_failed": "Impossible de restaurer la partie '{part:s}' du système",
"backup_couldnt_bind": "Impossible de lier {src:s} avec {dest:s}.",
"domain_dns_conf_is_just_a_recommendation": "Cette page montre la configuration *recommandée*. Elle ne configure *pas* le DNS pour vous. Il est de votre responsabilité que de configurer votre zone DNS chez votre fournisseur/registrar DNS avec cette recommandation.",
"domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost. Soit YunoHost n’est pas correctement connecté à internet, soit le serveur de dynette est en panne ou ne répond pas. Erreur : {error}",
"migrations_backward": "Migration en arrière.",
- "migrations_bad_value_for_target": "Nombre invalide pour le paramètre « target », les numéros de migration sont ou {}",
+ "migrations_bad_value_for_target": "Nombre invalide pour le paramètre target, les numéros de migration sont 0 ou {}",
"migrations_cant_reach_migration_file": "Impossible d’accéder aux fichiers de migrations avec le chemin %s",
"migrations_current_target": "La cible de migration est {}",
"migrations_error_failed_to_load_migration": "ERREUR : échec du chargement de migration {number} {name}",
"migrations_forward": "Migration en avant",
- "migrations_loading_migration": "Chargement de la migration {number} {name}…",
- "migrations_migration_has_failed": "La migration {number} {name} a échoué avec l’exception {exception}, annulation",
+ "migrations_loading_migration": "Chargement de la migration {number} {name} …",
+ "migrations_migration_has_failed": "La migration {number} {name} a échoué avec l’exception {exception} : annulation",
"migrations_no_migrations_to_run": "Aucune migration à lancer",
- "migrations_show_currently_running_migration": "Application de la migration {number} {name}…",
+ "migrations_show_currently_running_migration": "Application de la migration {number} {name} …",
"migrations_show_last_migration": "La dernière migration appliquée est {}",
- "migrations_skip_migration": "Omission de la migration {number} {name}…",
- "server_shutdown": "Le serveur sera éteint",
- "server_shutdown_confirm": "Le serveur immédiatement être éteint, le voulez-vous vraiment ? [{answers:s}]",
+ "migrations_skip_migration": "Ignorer et passer la migration {number} {name} …",
+ "server_shutdown": "Le serveur va éteindre",
+ "server_shutdown_confirm": "Le serveur va être éteint immédiatement, le voulez-vous vraiment ? [{answers:s}]",
"server_reboot": "Le serveur va redémarrer",
"server_reboot_confirm": "Le serveur va redémarrer immédiatement, le voulez-vous vraiment ? [{answers:s}]",
"app_upgrade_some_app_failed": "Impossible de mettre à jour certaines applications",
@@ -372,35 +372,35 @@
"app_upgrade_app_name": "Mise à jour de l’application {app} …",
"backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives '{path:s}'. Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas, vous avez probablement oublié de monter ou de connecter votre disque dur ou votre clef USB.",
"migrate_tsig_end": "La migration à hmac-sha512 est terminée",
- "migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué, annulation des modifications. Erreur : {error_code} - {error}",
- "migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine « {domain} », lancement de la migration vers hmac-sha512 qui est plus sécurisé",
+ "migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué. Annulation des modifications. Erreur : {error_code} - {error}",
+ "migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine '{domain}', lancement de la migration vers hmac-sha512 qui est plus sécurisé",
"migrate_tsig_wait": "Attendre 3 minutes pour que le serveur DynDNS prenne en compte la nouvelle clef …",
"migrate_tsig_wait_2": "2 minutes …",
"migrate_tsig_wait_3": "1 minute …",
"migrate_tsig_wait_4": "30 secondes …",
"migrate_tsig_not_needed": "Il ne semble pas que vous utilisez un domaine DynDNS, donc aucune migration n’est nécessaire !",
"app_checkurl_is_deprecated": "Packagers /!\\ 'app checkurl' est obsolète ! Utilisez 'app register-url' en remplacement !",
- "migration_description_0001_change_cert_group_to_sslcert": "Change les permissions de groupe des certificats de 'metronome' à 'ssl-cert'",
- "migration_description_0002_migrate_to_tsig_sha256": "Améliore la sécurité de DynDNS TSIG en utilisant SHA512 au lieu de MD5",
+ "migration_description_0001_change_cert_group_to_sslcert": "Changement des permissions de groupe des certificats de 'metronome' à 'ssl-cert'",
+ "migration_description_0002_migrate_to_tsig_sha256": "Amélioration de la sécurité de DynDNS TSIG en utilisant SHA512 au lieu de MD5",
"migration_description_0003_migrate_to_stretch": "Mise à niveau du système vers Debian Stretch et YunoHost 3.0",
"migration_0003_backward_impossible": "La migration Stretch n’est pas réversible.",
"migration_0003_start": "Démarrage de la migration vers Stretch. Les journaux seront disponibles dans {logfile}.",
- "migration_0003_patching_sources_list": "Modification de sources.lists …",
+ "migration_0003_patching_sources_list": "Modification du fichier sources.lists …",
"migration_0003_main_upgrade": "Démarrage de la mise à niveau principale …",
"migration_0003_fail2ban_upgrade": "Démarrage de la mise à niveau de fail2ban …",
"migration_0003_restoring_origin_nginx_conf": "Votre fichier /etc/nginx/nginx.conf a été modifié d’une manière ou d’une autre. La migration va d’abords le réinitialiser à son état initial. Le fichier précédent sera disponible en tant que {backup_dest}.",
- "migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du paquet YunoHost. La migration se terminera, mais la mise à jour réelle aura lieu immédiatement après. Après cette opération terminée, vous pourriez avoir à vous reconnecter à l’administration via le panel web.",
+ "migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du paquet YunoHost. La migration se terminera, mais la mise à jour réelle aura lieu immédiatement après. Une fois cette opération terminée, vous pourriez avoir à vous reconnecter à l’administration via le panel web.",
"migration_0003_not_jessie": "La distribution Debian actuelle n’est pas Jessie !",
"migration_0003_system_not_fully_up_to_date": "Votre système n’est pas complètement à jour. Veuillez mener une mise à jour classique avant de lancer à migration à Stretch.",
- "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est ma passé pendant la mise à niveau principale : le système est toujours sur Jessie ?!? Pour investiguer le problème, veuillez regarder les journaux {log} 🙁…",
- "migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nDe plus, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence !",
- "migration_0003_problematic_apps_warning": "Veuillez noter que les applications suivantes, éventuellement problématiques, ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées «working ». En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront après la mise à niveau : {problematic_apps}",
+ "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Jessie !? Pour en savoir plus et investiguer sur ce problème, veuillez regarder les journaux {log}:s .",
+ "migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nEn outre, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence !",
+ "migration_0003_problematic_apps_warning": "Veuillez noter que des applications possiblement problématiques ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées comme 'fonctionnelles'/'working'. En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront après la mise à niveau : {problematic_apps}",
"migration_0003_modified_files": "Veuillez noter que les fichiers suivants ont été détectés comme modifiés manuellement et pourraient être écrasés à la fin de la mise à niveau : {manually_modified_files}",
"migrations_list_conflict_pending_done": "Vous ne pouvez pas utiliser --previous et --done simultanément.",
- "migrations_to_be_ran_manually": "La migration {number} {name} doit être lancée manuellement. Veuillez aller dans Outils > Migration dans l’interface admin, ou lancer `yunohost tools migrations migrate`.",
+ "migrations_to_be_ran_manually": "La migration {number} {name} doit être lancée manuellement. Veuillez aller dans Outils > Migrations dans l’interface admin, ou lancer `yunohost tools migrations migrate`.",
"migrations_need_to_accept_disclaimer": "Pour lancer la migration {number} {name}, vous devez accepter cette clause de non-responsabilité :\n---\n{disclaimer}\n---\nSi vous acceptez de lancer la migration, veuillez relancer la commande avec l’option --accept-disclaimer.",
"service_description_avahi-daemon": "permet d’atteindre votre serveur via yunohost.local sur votre réseau local",
- "service_description_dnsmasq": "assure la résolution des noms de domaine (DNS)",
+ "service_description_dnsmasq": "gère la résolution des noms de domaine (DNS)",
"service_description_dovecot": "permet aux clients de messagerie d’accéder/récupérer les courriels (via IMAP et POP3)",
"service_description_fail2ban": "protège contre les attaques brute-force et autres types d’attaques venant d’Internet",
"service_description_glances": "surveille les informations système de votre serveur",
@@ -410,43 +410,43 @@
"service_description_nslcd": "gère la connexion en ligne de commande des utilisateurs YunoHost",
"service_description_php5-fpm": "exécute des applications écrites en PHP avec nginx",
"service_description_postfix": "utilisé pour envoyer et recevoir des courriels",
- "service_description_redis-server": "une base de donnée spécialisée utilisée pour l’accès rapide aux données, les files d’attentes et la communication inter-programmes",
+ "service_description_redis-server": "une base de données spécialisée utilisée pour l’accès rapide aux données, les files d’attentes et la communication entre les programmes",
"service_description_rmilter": "vérifie divers paramètres dans les courriels",
"service_description_rspamd": "filtre le pourriel, et d’autres fonctionnalités liées au courriel",
"service_description_slapd": "stocke les utilisateurs, domaines et leurs informations liées",
"service_description_ssh": "vous permet de vous connecter à distance à votre serveur via un terminal (protocole SSH)",
"service_description_yunohost-api": "permet les interactions entre l’interface web de YunoHost et le système",
- "service_description_yunohost-firewall": "gère les ports de connexion ouverts et fermés aux services",
+ "service_description_yunohost-firewall": "gère l'ouverture et la fermeture des ports de connexion aux services",
"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 metadata associé aux logs est corrompu : {md_file}",
+ "log_corrupted_md_file": "Le fichier yaml de metadata associé aux logs est corrompu : '{md_file}'",
"log_category_404": "Le journal de la catégorie '{category}' n’existe pas",
- "log_link_to_log": "Log complet de cette opération : ' {desc} '",
- "log_help_to_get_log": "Pour voir le log de cette opération '{desc}', utiliser la commande 'yunohost log display {name}'",
- "log_link_to_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de fournir le log complet de l’opération en cliquant ici",
+ "log_link_to_log": "Journal historisé complet de cette opération : ' {desc} '",
+ "log_help_to_get_log": "Pour voir le journal historisé de cette opération '{desc}', utilisez la commande 'yunohost log display {name}'",
+ "log_link_to_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de fournir le journal historisé complet de l’opération en cliquant ici",
"backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge php7, vos applications php pourraient ne pas être restaurées (reason: {error:s})",
- "log_help_to_get_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de partager le log de cette opération en utilisant la commande 'yunohost log display {name} --share'",
- "log_does_exists": "Il n’existe pas de log de l’opération ayant pour nom '{log}', utiliser 'yunohost log list pour voir tous les fichiers de logs disponibles'",
- "log_operation_unit_unclosed_properly": "L’opération ne s’est pas terminée correctement",
- "log_app_addaccess": "Ajouter l’accès à '{}'",
- "log_app_removeaccess": "Enlever l’accès à '{}'",
+ "log_help_to_get_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de partager le journal historisé de cette opération en utilisant la commande 'yunohost log display {name} --share'",
+ "log_does_exists": "Il n’existe pas de journal historisé de l’opération ayant pour nom '{log}', utiliser 'yunohost log list pour voir tous les fichiers de journaux historisés disponibles'",
+ "log_operation_unit_unclosed_properly": "L’opération ne s’est pas fermée/terminée correctement",
+ "log_app_addaccess": "Ajouter l’accès à '{}'",
+ "log_app_removeaccess": "Enlever l’accès à '{}'",
"log_app_clearaccess": "Retirer tous les accès à '{}'",
"log_app_fetchlist": "Ajouter une liste d’application",
"log_app_removelist": "Enlever une liste d’application",
- "log_app_change_url": "Changer l’url de l’application '{}'",
+ "log_app_change_url": "Changer l’URL de l’application '{}'",
"log_app_install": "Installer l’application '{}'",
"log_app_remove": "Enlever l’application '{}'",
"log_app_upgrade": "Mettre à jour l’application '{}'",
- "log_app_makedefault": "Faire de '{}' l’application par défaut",
- "log_available_on_yunopaste": "Le log est désormais disponible via {url}",
+ "log_app_makedefault": "Faire de '{}' l’application par défaut",
+ "log_available_on_yunopaste": "Le journal historisé est désormais disponible via {url}",
"log_backup_restore_system": "Restaurer le système depuis une archive de sauvegarde",
"log_backup_restore_app": "Restaurer '{}' depuis une sauvegarde",
- "log_remove_on_failed_restore": "Retirer '{}' après la restauration depuis une sauvegarde qui a échouée",
+ "log_remove_on_failed_restore": "Retirer '{}' après un échec de restauration depuis une archive de sauvegarde",
"log_remove_on_failed_install": "Enlever '{}' après une installation échouée",
"log_domain_add": "Ajouter le domaine '{}' dans la configuration du système",
"log_domain_remove": "Enlever le domaine '{}' de la configuration du système",
"log_dyndns_subscribe": "Souscrire au sous-domaine YunoHost '{}'",
"log_dyndns_update": "Mettre à jour l’adresse IP associée à votre sous-domaine YunoHost '{}'",
- "log_letsencrypt_cert_install": "Installer le certificat Let’s Encrypt sur le domaine '{}'",
+ "log_letsencrypt_cert_install": "Installer le certificat Let’s Encrypt sur le domaine '{}'",
"log_selfsigned_cert_install": "Installer le certificat auto-signé sur le domaine '{}'",
"log_letsencrypt_cert_renew": "Renouveler le certificat Let’s Encrypt de '{}'",
"log_service_enable": "Activer le service '{}'",
@@ -461,26 +461,26 @@
"log_tools_upgrade": "Mise à jour des paquets Debian",
"log_tools_shutdown": "Éteindre votre serveur",
"log_tools_reboot": "Redémarrer votre serveur",
- "mail_unavailable": "Cette adresse mail est réservée et doit être automatiquement attribuée au tout premier utilisateur",
- "migration_description_0004_php5_to_php7_pools": "Reconfigurez le pool PHP pour utiliser PHP 7 au lieu de 5",
- "migration_description_0005_postgresql_9p4_to_9p6": "Migration des bases de données de postgresql 9.4 vers 9.6",
- "migration_0005_postgresql_94_not_installed": "Postgresql n’a pas été installé sur votre système. Rien à faire !",
- "migration_0005_postgresql_96_not_installed": "Postgresql 9.4 a été trouvé et installé, mais pas Postgresql 9.6 !? Quelque chose d’étrange a dû arriver à votre système :( …",
+ "mail_unavailable": "Cette adresse de courriel est réservée et doit être automatiquement attribuée au tout premier utilisateur",
+ "migration_description_0004_php5_to_php7_pools": "Reconfigurez le pool PHP pour utiliser PHP 7 au lieu de PHP 5",
+ "migration_description_0005_postgresql_9p4_to_9p6": "Migration des bases de données de PostgreSQL 9.4 vers PostgreSQL 9.6",
+ "migration_0005_postgresql_94_not_installed": "PostgreSQL n’a pas été installé sur votre système. Rien à faire !",
+ "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 a été trouvé et installé, mais pas PostgreSQL 9.6 !? Quelque chose d’étrange a dû arriver à votre système :( …",
"migration_0005_not_enough_space": "Il n’y a pas assez d’espace libre de disponible sur {path} pour lancer maintenant la migration :(.",
- "recommend_to_add_first_user": "La post-installation est terminée, mais YunoHost a besoin d’au moins un utilisateur pour fonctionner correctement. Vous devez en ajouter un en utilisant « yunohost user create » ou l’interface d’administration.",
- "service_description_php7.0-fpm": "exécute des applications écrites en PHP avec nginx",
+ "recommend_to_add_first_user": "La post-installation est terminée. YunoHost a besoin d’au moins un utilisateur pour fonctionner correctement. Vous devez en ajouter un en utilisant 'yunohost user create' ou bien via l’interface d’administration web.",
+ "service_description_php7.0-fpm": "exécute des applications écrites en PHP avec Nginx",
"users_available": "Liste des utilisateurs disponibles :",
"good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères — bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou d'utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
- "migration_0006_disclaimer": "Yunohost s’attend maintenant à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
+ "migration_0006_disclaimer": "YunoHost s’attendra à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
"migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.",
- "password_listed": "Ce mot de passe est l'un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d'un peu plus unique.",
+ "password_listed": "Ce mot de passe est l'un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d'un peu plus singulier.",
"password_too_simple_1": "Le mot de passe doit comporter au moins 8 caractères",
"password_too_simple_2": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules et des minuscules",
"password_too_simple_3": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
"password_too_simple_4": "Le mot de passe doit comporter au moins 12 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
- "root_password_desynchronized": "Le mot de passe administrateur a été changé, mais YunoHost n’a pas pu le propager sur le mot de passe root !",
+ "root_password_desynchronized": "Le mot de passe administrateur a été changé, mais YunoHost n’a pas pu le propager au mot de passe root !",
"aborting": "Interruption de la procédure.",
"app_not_upgraded": "Les applications suivantes n'ont pas été mises à jour : {apps}",
"app_start_install": "Installation de l'application {app} …",
@@ -516,11 +516,11 @@
"pattern_password_app": "Désolé, les mots de passe ne doivent pas contenir les caractères suivants : {forbidden_chars}",
"root_password_replaced_by_admin_password": "Votre mot de passe root a été remplacé par votre mot de passe administrateur.",
"service_conf_now_managed_by_yunohost": "Le fichier de configuration '{conf}' est maintenant géré par YunoHost.",
- "service_reload_failed": "Impossible de recharger le service '{service:s}'.\n\nJournaux récents de ce service : {logs:s}",
+ "service_reload_failed": "Impossible de recharger le service '{service:s}'.\n\nJournaux historisés récents de ce service : {logs:s}",
"service_reloaded": "Le service '{service:s}' a été rechargé",
- "service_restart_failed": "Impossible de redémarrer le service '{service:s}'\n\nJournaux récents de ce service : {logs:s}",
+ "service_restart_failed": "Impossible de redémarrer le service '{service:s}'\n\nJournaux historisés récents de ce service : {logs:s}",
"service_restarted": "Le service '{service:s}' a été redémarré",
- "service_reload_or_restart_failed": "Impossible de recharger ou de redémarrer le service '{service:s}'\n\nJournaux récents de ce service : {logs:s}",
+ "service_reload_or_restart_failed": "Impossible de recharger ou de redémarrer le service '{service:s}'\n\nJournaux historisés récents de ce service : {logs:s}",
"service_reloaded_or_restarted": "Le service '{service:s}' a été rechargé ou redémarré",
- "this_action_broke_dpkg": "Cette action a laissé des paquets non configurés par dpkg/apt (les gestionnaires de paquets système). Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a'."
+ "this_action_broke_dpkg": "Cette action a laissé des paquets non configurés par dpkg/apt (les gestionnaires de paquets système). Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a`."
}
From 8954caa39d22cf59f07f90aa6d7ede925a2b60a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Quent=C3=AD?=
Date: Sun, 17 Mar 2019 18:44:20 +0000
Subject: [PATCH 165/199] Translated using Weblate (Occitan)
Currently translated at 95.6% (482 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/oc/
---
locales/oc.json | 48 ++++++++++++++++++++++++++++++++++--------------
1 file changed, 34 insertions(+), 14 deletions(-)
diff --git a/locales/oc.json b/locales/oc.json
index 91b455210..433da4478 100644
--- a/locales/oc.json
+++ b/locales/oc.json
@@ -13,7 +13,7 @@
"app_not_properly_removed": "{app:s} es pas estat corrèctament suprimit",
"app_removed": "{app:s} es estat suprimit",
"app_unknown": "Aplicacion desconeguda",
- "app_upgrade_app_name": "Mesa a jorn de l’aplicacion {app}...",
+ "app_upgrade_app_name": "Mesa a jorn de l’aplicacion {app}…",
"app_upgrade_failed": "Impossible de metre a jorn {app:s}",
"app_upgrade_some_app_failed": "D’aplicacions se pòdon pas metre a jorn",
"app_upgraded": "{app:s} es estat mes a jorn",
@@ -52,7 +52,7 @@
"app_location_already_used": "L’aplicacion « {app} » es ja installada a aqueste emplaçament ({path})",
"app_manifest_invalid": "Manifest d’aplicacion incorrècte : {error}",
"app_package_need_update": "Lo paquet de l’aplicacion {app} deu èsser mes a jorn per seguir los cambiaments de YunoHost",
- "app_requirements_checking": "Verificacion dels paquets requesida per {app}...",
+ "app_requirements_checking": "Verificacion dels paquets requesits per {app}…",
"app_sources_fetch_failed": "Recuperacion dels fichièrs fonts impossibla",
"app_unsupported_remote_type": "Lo tipe alonhat utilizat per l’aplicacion es pas suportat",
"appslist_retrieve_error": "Impossible de recuperar la lista d’aplicacions alonhadas {appslist:s} : {error:s}",
@@ -64,7 +64,7 @@
"backup_cleaning_failed": "Impossible de netejar lo repertòri temporari de salvagarda",
"backup_copying_to_organize_the_archive": "Còpia de {size:s} Mio per organizar l’archiu",
"backup_created": "Salvagarda acabada",
- "backup_creating_archive": "Creacion de l’archiu de salvagarda...",
+ "backup_creating_archive": "Creacion de l’archiu de salvagarda…",
"backup_creation_failed": "Impossible de crear la salvagarda",
"app_already_installed_cant_change_url": "Aquesta aplicacion es ja installada. Aquesta foncion pòt pas simplament cambiar l’URL. Agachatz « app changeurl » s’es disponible.",
"app_change_no_change_url_script": "L’aplicacion {app_name:s} pren pas en compte lo cambiament d’URL, poiretz aver de la metre a jorn.",
@@ -83,7 +83,7 @@
"backup_output_directory_not_empty": "Lo dorsièr de sortida es pas void",
"backup_output_directory_required": "Vos cal especificar un dorsièr de sortida per la salvagarda",
"backup_running_app_script": "Lançament de l’escript de salvagarda de l’aplicacion « {app:s} »...",
- "backup_running_hooks": "Execucion dels scripts de salvagarda...",
+ "backup_running_hooks": "Execucion dels scripts de salvagarda…",
"backup_system_part_failed": "Impossible de salvagardar la part « {part:s} » del sistèma",
"app_requirements_failed": "Impossible de complir las condicions requesidas per {app} : {error}",
"app_requirements_unmeet": "Las condicions requesidas per {app} son pas complidas, lo paquet {pkgname} ({version}) deu èsser {spec}",
@@ -112,7 +112,7 @@
"upnp_port_open_failed": "Impossible de dobrir los pòrts amb UPnP",
"yunohost_already_installed": "YunoHost es ja installat",
"yunohost_configured": "YunoHost es estat configurat",
- "yunohost_installing": "Installacion de YunoHost...",
+ "yunohost_installing": "Installacion de YunoHost…",
"backup_applying_method_borg": "Mandadís de totes los fichièrs a la salvagarda dins lo repertòri borg-backup…",
"backup_csv_creation_failed": "Creacion impossibla del fichièr CSV necessari a las operacions futuras de restauracion",
"backup_extracting_archive": "Extraccion de l’archiu de salvagarda…",
@@ -161,7 +161,7 @@
"dyndns_cron_removed": "La tasca cron pel domeni DynDNS es levada",
"dyndns_ip_update_failed": "Impossible d’actualizar l’adreça IP sul domeni DynDNS",
"dyndns_ip_updated": "Vòstra adreça IP es estada actualizada pel domeni DynDNS",
- "dyndns_key_generating": "La clau DNS es a se generar, pòt trigar una estona...",
+ "dyndns_key_generating": "La clau DNS es a se generar, pòt trigar una estona…",
"dyndns_key_not_found": "Clau DNS introbabla pel domeni",
"dyndns_no_domain_registered": "Cap de domeni pas enregistrat amb DynDNS",
"dyndns_registered": "Lo domeni DynDNS es enregistrat",
@@ -313,7 +313,7 @@
"service_conf_would_be_updated": "La configuracion del servici « {service} » seriá estada actualizada",
"service_description_avahi-daemon": "permet d’aténher vòstre servidor via yunohost.local sus vòstre ret local",
"service_description_dnsmasq": "gerís la resolucion dels noms de domeni (DNS)",
- "updating_apt_cache": "Actualizacion de la lista dels paquets disponibles...",
+ "updating_apt_cache": "Actualizacion de la lista dels paquets disponibles…",
"service_conf_file_backed_up": "Lo fichièr de configuracion « {conf} » es salvagardat dins « {backup} »",
"service_conf_file_copy_failed": "Còpia impossibla del nòu fichièr de configuracion « {new} » cap a « {conf} »",
"server_reboot_confirm": "Lo servidor es per reaviar sul pic, o volètz vertadièrament ? {answers:s}",
@@ -372,7 +372,7 @@
"migrate_tsig_start": "L’algorisme de generacion de claus es pas pro securizat per la signatura TSIG del domeni « {domain} », lançament de la migracion cap a hmac-sha512 que’s mai securizat",
"migration_description_0001_change_cert_group_to_sslcert": "Càmbia las permissions de grop dels certificats de « metronome » per « ssl-cert »",
"migration_0003_restoring_origin_nginx_conf": "Vòstre fichièr /etc/nginx/nginx.conf es estat modificat manualament. La migracion reïnicializarà d’en primièr son estat origina… Lo fichièr precedent serà disponible coma {backup_dest}.",
- "migration_0003_still_on_jessie_after_main_upgrade": "Quicòm a trucat pendent la mesa a nivèl màger : lo sistèma es encara jos Jessie ?!? Per trobar lo problèma, agachatz {log} …",
+ "migration_0003_still_on_jessie_after_main_upgrade": "Quicòm a trucat pendent la mesa a nivèl màger : lo sistèma es encara jos Jessie ?!? Per trobar lo problèma, agachatz {log}…",
"migration_0003_general_warning": "Notatz qu’aquesta migracion es una operacion delicata. Encara que la còla YunoHost aguèsse fach çò melhor per la tornar legir e provar, la migracion poiriá copar de parts del sistèma o de las aplicacions.\n\nEn consequéncia, vos recomandam :\n· · · · - de lançar una salvagarda de vòstras donadas o aplicacions criticas. Mai d’informacions a https://yunohost.org/backup ;\n· · · · - d’èsser pacient aprèp aver lançat la migracion : segon vòstra connexion Internet e material, pòt trigar qualques oras per que tot siá mes al nivèl.\n\nEn mai, lo pòrt per SMTP, utilizat pels clients de corrièls extèrns (coma Thunderbird o K9-Mail per exemple) foguèt cambiat de 465 (SSL/TLS) per 587 (STARTTLS). L’ancian pòrt 465 serà automaticament tampat e lo nòu pòrt 587 serà dobèrt dins lo parafuòc. Vosautres e vòstres utilizaires *auretz* d’adaptar la configuracion de vòstre client de corrièl segon aqueles cambiaments !",
"migration_0003_problematic_apps_warning": "Notatz que las aplicacions seguentas, saique problematicas, son estadas desactivadas. Semblan d’aver estadas installadas d’una lista d’aplicacions o que son pas marcadas coma «working ». En consequéncia, podèm pas assegurar que tendràn de foncionar aprèp la mesa a nivèl : {problematic_apps}",
"migrations_bad_value_for_target": "Nombre invalid pel paramètre « target », los numèros de migracion son 0 o {}",
@@ -457,14 +457,34 @@
"service_description_php7.0-fpm": "executa d’aplicacions escrichas en PHP amb nginx",
"users_available": "Lista dels utilizaires disponibles :",
"good_practices_about_admin_password": "Sètz per definir un nòu senhal per l’administracion. Lo senhal deu almens conténer 8 caractèrs - encara que siá de bon far d’utilizar un senhal mai long qu’aquò (ex. una passafrasa) e/o d’utilizar mantun tipes de caractèrs (majuscula, minuscula, nombre e caractèrs especials).",
- "good_practices_about_user_password": "Sètz per definir un nòu senhal d’utilizaire. Lo senhal deu almens conténer 8 caractèrs - encara que siá de bon far d’utilizar un senhal mai long qu’aquò (ex. una passafrasa) e/o d’utilizar mantun tipes de caractèrs (majuscula, minuscula, nombre e caractèrs especials).",
+ "good_practices_about_user_password": "Sètz a mand de definir un nòu senhal d’utilizaire. Lo nòu senhal deu conténer almens 8 caractèrs, es de bon far d’utilizar un senhal mai long (es a dire una frasa de senhal) e/o utilizar mantuns tipes de caractèrs (majusculas, minusculas, nombres e caractèrs especials).",
"migration_description_0006_sync_admin_and_root_passwords": "Sincronizar los senhals admin e root",
"migration_0006_disclaimer": "Ara YunoHost s’espèra que los senhals admin e root sián sincronizats. En lançant aquesta migracion, vòstre senhal root serà remplaçat pel senhal admin.",
"migration_0006_done": "Lo senhal root es estat remplaçat pel senhal admin.",
- "password_listed": "Aqueste senhal fa part dels senhals mai utilizats del monde. Volgatz ben ne causir un mai unic.",
+ "password_listed": "Aqueste senhal es un dels mai utilizats al monde. Se vos plai utilizatz-ne un mai unic.",
"password_too_simple_1": "Lo senhal deu conténer almens 8 caractèrs",
- "password_too_simple_2": "Lo senhal deu conténer almens 8 caractèrs amb de nombres, de majusculas e de minusculas",
- "password_too_simple_3": "Lo senhal deu conténer almens 8 caractèrs amb de nombres, de majusculas, de minusculas e de caractèrs especials",
- "password_too_simple_4": "Lo senhal deu conténer almens 12 caractèrs amb de nombres, de majusculas, de minusculas e de caractèrs especials",
- "root_password_desynchronized": "Lo senhal de l’administrator es estat cambiat, mas YunoHost a pas pogut l’espandir al senhal root !"
+ "password_too_simple_2": "Lo senhal deu conténer almens 8 caractèrs e numbres, majusculas e minusculas",
+ "password_too_simple_3": "Lo senhal deu conténer almens 8 caractèrs e nombres, majusculas e minusculas e caractèrs especials",
+ "password_too_simple_4": "Lo senhal deu conténer almens 12 caractèrs, de nombre, majusculas, minisculas e caractèrs specials",
+ "root_password_desynchronized": "Lo senhal de l’administrator es estat cambiat, mas YunoHost a pas pogut l’espandir al senhal root !",
+ "aborting": "Interrupcion.",
+ "app_not_upgraded": "Las aplicacions seguentas son pas estadas actualizadas : {apps}",
+ "app_start_install": "Installacion de l’aplicacion {app}…",
+ "app_start_remove": "Supression de l’aplicacion {app}…",
+ "app_start_backup": "Recuperacion dels fichièrs de salvagardar per {app}…",
+ "app_start_restore": "Restauracion de l’aplicacion {app}…",
+ "app_upgrade_several_apps": "Las aplicacions seguentas seràn mesas a jorn : {apps}",
+ "ask_new_domain": "Nòu domeni",
+ "ask_new_path": "Nòu camin",
+ "backup_actually_backuping": "Creacion d’un archiu de seguretat a partir dels fichièrs recuperats…",
+ "backup_mount_archive_for_restore": "Preparacion de l’archiu per restauracion…",
+ "dyndns_could_not_check_available": "Verificacion impossibla de la disponibilitat de {domain:s} sus {provider:s}.",
+ "file_does_not_exist": "Lo camin {path:s} existís pas.",
+ "global_settings_setting_security_password_admin_strength": "Fòrça del senhal administrator",
+ "global_settings_setting_security_password_user_strength": "Fòrça del senhal utilizaire",
+ "migration_description_0007_ssh_conf_managed_by_yunohost_step1": "La configuracion SSH serà gerada per YunoHost (etapa 1, automatica)",
+ "migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Daissar YunoHost gerir la configuracion SSH (etapa 2, manuala)",
+ "migration_0007_cancelled": "YunoHost a pas reüssit a melhorar lo biais de gerir la configuracion SSH.",
+ "root_password_replaced_by_admin_password": "Lo senhal root es estat remplaçat pel senhal administrator.",
+ "service_restarted": "Lo servici '{service:s}' es estat reaviat"
}
From 70ebf9b121778bda831cbb586cfe569394ae6ea2 Mon Sep 17 00:00:00 2001
From: xaloc33
Date: Thu, 21 Mar 2019 10:07:28 +0000
Subject: [PATCH 166/199] Translated using Weblate (Catalan)
Currently translated at 31.7% (160 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ca/
---
locales/ca.json | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 47 insertions(+), 1 deletion(-)
diff --git a/locales/ca.json b/locales/ca.json
index 44d473d91..dd01ddebb 100644
--- a/locales/ca.json
+++ b/locales/ca.json
@@ -112,5 +112,51 @@
"password_too_simple_1": "La contrasenya ha de tenir un mínim de 8 caràcters",
"password_too_simple_2": "La contrasenya ha de tenir un mínim de 8 caràcters i ha de contenir dígits, majúscules i minúscules",
"password_too_simple_3": "La contrasenya ha de tenir un mínim de 8 caràcters i tenir dígits, majúscules, minúscules i caràcters especials",
- "password_too_simple_4": "La contrasenya ha de tenir un mínim de 12 caràcters i tenir dígits, majúscules, minúscules i caràcters especials"
+ "password_too_simple_4": "La contrasenya ha de tenir un mínim de 12 caràcters i tenir dígits, majúscules, minúscules i caràcters especials",
+ "backup_no_uncompress_archive_dir": "El directori de l'arxiu descomprimit no existeix",
+ "backup_nothings_done": "No hi ha res a guardar",
+ "backup_output_directory_forbidden": "Directori de sortida no permès. Les còpies de seguretat no es poden crear ni dins els directoris /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ni dins els subdirectoris /home/yunohost.backup/archives",
+ "backup_output_directory_not_empty": "El directori de sortida no està buit",
+ "backup_output_directory_required": "Heu d'especificar un directori de sortida per la còpia de seguretat",
+ "backup_output_symlink_dir_broken": "Teniu un enllaç simbòlic trencat en lloc del directori dels arxius '{path:s}'. Pot ser teniu una configuració per la còpia de seguretat específica en un altre sistema de fitxers, si és el cas segurament heu oblidat muntar o connectar el disc dur o la clau USB.",
+ "backup_php5_to_php7_migration_may_fail": "No s'ha pogut convertir l'arxiu per suportar php7, la restauració de les vostres aplicacions pot fallar (raó: {error:s})",
+ "backup_running_hooks": "Executant els scripts de la còpia de seguretat…",
+ "backup_system_part_failed": "No s'ha pogut fer la còpia de seguretat de la part \"{part:s}\" del sistema",
+ "backup_unable_to_organize_files": "No s'han pogut organitzar els fitxers dins de l'arxiu amb el mètode ràpid",
+ "backup_with_no_backup_script_for_app": "L'aplicació {app:s} no té un script de còpia de seguretat. Serà ignorat.",
+ "backup_with_no_restore_script_for_app": "L'aplicació {app:s} no té un script de restauració, no podreu restaurar automàticament la còpia de seguretat d'aquesta aplicació.",
+ "certmanager_acme_not_configured_for_domain": "El certificat pel domini {domain:s} sembla que no està instal·lat correctament. Si us plau executeu primer cert-install per aquest domini.",
+ "certmanager_attempt_to_renew_nonLE_cert": "El certificat pel domini {domain:s} no ha estat emès per Let's Encrypt. No es pot renovar automàticament!",
+ "certmanager_attempt_to_renew_valid_cert": "El certificat pel domini {domain:s} està a punt de caducar! Utilitzeu --force per ometre",
+ "certmanager_attempt_to_replace_valid_cert": "Esteu intentant sobreescriure un certificat correcte i vàlid pel domini {domain:s}! (Utilitzeu --force per ometre)",
+ "certmanager_cannot_read_cert": "S'ha produït un error al intentar obrir el certificat actual pel domini {domain:s} (arxiu: {file:s}), raó: {reason:s}",
+ "certmanager_cert_install_success": "S'ha instal·lat correctament un certificat Let's Encrypt pel domini {domain:s}!",
+ "certmanager_cert_install_success_selfsigned": "S'ha instal·lat correctament un certificat auto-signat pel domini {domain:s}!",
+ "certmanager_cert_renew_success": "S'ha renovat correctament el certificat Let's Encrypt pel domini {domain:s}!",
+ "certmanager_cert_signing_failed": "No s'ha pogut firmar el nou certificat",
+ "certmanager_certificate_fetching_or_enabling_failed": "Sembla que l'activació del nou certificat per {domain:s} ha fallat…",
+ "certmanager_conflicting_nginx_file": "No s'ha pogut preparar el domini per al desafiament ACME: l'arxiu de configuració nginx {filepath:s} entra en conflicte i s'ha d'eliminar primer",
+ "certmanager_couldnt_fetch_intermediate_cert": "S'ha exhaurit el temps d'esperar al intentar recollir el certificat intermedi des de Let's Encrypt. La instal·lació/renovació del certificat s'ha cancel·lat - torneu a intentar-ho més tard.",
+ "certmanager_domain_cert_not_selfsigned": "El certificat pel domini {domain:s} no és auto-signat Esteu segur de voler canviar-lo? (Utilitzeu --force per fer-ho)",
+ "certmanager_domain_dns_ip_differs_from_public_ip": "El registre DNS \"A\" pel domini {domain:s} és diferent a l'adreça IP d'aquest servidor. Si heu modificat recentment el registre A, si us plau espereu a que es propagui (hi ha eines per verificar la propagació disponibles a internet). (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)",
+ "certmanager_domain_http_not_working": "Sembla que el domini {domain:s} no és accessible via HTTP. Si us plau verifiqueu que les configuracions DNS i nginx siguin correctes",
+ "certmanager_domain_not_resolved_locally": "El domini {domain:s} no es pot resoldre dins del vostre servidor YunoHost. Això pot passar si heu modificat recentment el registre DNS. Si és així, si us plau espereu unes hores per a que es propagui. Si el problema continua, considereu afegir {domain:s} a /etc/hosts. (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)",
+ "certmanager_domain_unknown": "Domini desconegut {domain:s}",
+ "certmanager_error_no_A_record": "No s'ha trobat cap registre DNS \"A\" per {domain:s}. Heu de fer que el vostre nom de domini apunti cap a la vostra màquina per tal de poder instal·lar un certificat Let's Encrypt! (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)",
+ "certmanager_hit_rate_limit": "S'han emès massa certificats recentment per aquest mateix conjunt de dominis {domain:s}. Si us plau torneu-ho a intentar més tard. Consulteu https://letsencrypt.org/docs/rate-limits/ per obtenir més detalls",
+ "certmanager_http_check_timeout": "S'ha exhaurit el temps d'espera quan el servidor ha intentat contactar amb ell mateix via HTTP utilitzant la seva adreça IP pública (domini domain:s} amb IP {ip:s}). Pot ser degut a hairpinning o a que el talla focs/router al que està connectat el servidor estan mal configurats.",
+ "certmanager_no_cert_file": "No s'ha pogut llegir l'arxiu del certificat pel domini {domain:s} (fitxer: {file:s})",
+ "certmanager_self_ca_conf_file_not_found": "No s'ha trobat el fitxer de configuració per l'autoritat del certificat auto-signat (fitxer: {file:s})",
+ "certmanager_unable_to_parse_self_CA_name": "No s'ha pogut analitzar el nom de l'autoritat del certificat auto-signat (fitxer: {file:s})",
+ "confirm_app_install_warning": "Atenció: aquesta aplicació funciona però no està ben integrada amb YunoHost. Algunes característiques com la autenticació única i la còpia de seguretat/restauració poden no estar disponibles. Voleu instal·lar-la de totes maneres? [{answers:s}] ",
+ "confirm_app_install_danger": "ATENCIÓ! Aquesta aplicació encara és experimental (si no és que no funciona directament) i és probable que trenqui el sistema! No hauríeu d'instal·lar-la a no ser que sapigueu el que feu. Esteu segurs de voler córrer aquest risc? [{answers:s}] ",
+ "confirm_app_install_thirdparty": "ATENCIÓ! La instal·lació d'aplicacions de terceres parts pot comprometre la integritat i seguretat del seu sistema. Faci-ho sota la seva responsabilitat.No hauríeu d'instal·lar-ne a no ser que sapigueu el que feu. Esteu segurs de voler córrer aquest risc? [{answers:s}] ",
+ "custom_app_url_required": "Heu de especificar una URL per actualitzar la vostra aplicació personalitzada {app:s}",
+ "custom_appslist_name_required": "Heu d'especificar un nom per la vostra llista d'aplicacions personalitzada",
+ "diagnosis_debian_version_error": "No s'ha pogut obtenir la versió Debian: {error}",
+ "diagnosis_kernel_version_error": "No s'ha pogut obtenir la versió del nucli: {error}",
+ "diagnosis_monitor_disk_error": "No es poden monitorar els discs: {error}",
+ "diagnosis_monitor_network_error": "No es pot monitorar la xarxa: {error}",
+ "diagnosis_monitor_system_error": "No es pot monitorar el sistema: {error}",
+ "diagnosis_no_apps": "No hi ha cap aplicació instal·lada"
}
From ce596a401aebe364e98e97543b240280b450a537 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste Holcroft
Date: Fri, 22 Mar 2019 05:48:11 +0000
Subject: [PATCH 167/199] Translated using Weblate (French)
Currently translated at 97.0% (489 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
---
locales/fr.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/locales/fr.json b/locales/fr.json
index 58c25d3ad..1948751da 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -471,7 +471,7 @@
"service_description_php7.0-fpm": "exécute des applications écrites en PHP avec Nginx",
"users_available": "Liste des utilisateurs disponibles :",
"good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
- "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères — bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou d'utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
+ "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères — bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
"migration_0006_disclaimer": "YunoHost s’attendra à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
"migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.",
@@ -481,7 +481,7 @@
"password_too_simple_3": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
"password_too_simple_4": "Le mot de passe doit comporter au moins 12 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
"root_password_desynchronized": "Le mot de passe administrateur a été changé, mais YunoHost n’a pas pu le propager au mot de passe root !",
- "aborting": "Interruption de la procédure.",
+ "aborting": "Interruption.",
"app_not_upgraded": "Les applications suivantes n'ont pas été mises à jour : {apps}",
"app_start_install": "Installation de l'application {app} …",
"app_start_remove": "Suppression de l'application {app} …",
From fc43640ae2fa660b2663870741926f6a47e80b94 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A9lanie=20Chauvel?=
Date: Fri, 22 Mar 2019 20:37:49 +0000
Subject: [PATCH 168/199] Translated using Weblate (French)
Currently translated at 98.8% (498 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
---
locales/fr.json | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/locales/fr.json b/locales/fr.json
index 1948751da..d8d3edbb1 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -120,7 +120,7 @@
"ldap_initialized": "L’annuaire LDAP a été initialisé",
"license_undefined": "indéfinie",
"mail_alias_remove_failed": "Impossible de supprimer l’alias de courriel '{mail:s}'",
- "mail_domain_unknown": "Le domaine '{domain:s}' est inconnu pour cette adresse de courriel",
+ "mail_domain_unknown": "Le domaine « {domain:s} » du courriel est inconnu",
"mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert '{mail:s}'",
"maindomain_change_failed": "Impossible de modifier le domaine principal",
"maindomain_changed": "Le domaine principal a été modifié",
@@ -153,7 +153,7 @@
"packages_upgrade_critical_later": "Les paquets critiques ({packages:s}) seront mis à jour ultérieurement",
"packages_upgrade_failed": "Impossible de mettre à jour tous les paquets",
"path_removal_failed": "Impossible de supprimer le chemin {:s}",
- "pattern_backup_archive_name": "Doit être un nom de fichier valide avec un maximum de 30 caractères, et composé uniquement de caractères alphanumériques et de tirets tels que -_.",
+ "pattern_backup_archive_name": "Doit être un nom de fichier valide avec un maximum de 30 caractères, et composé de caractères alphanumériques et -_. uniquement",
"pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.fr)",
"pattern_email": "Doit être une adresse de courriel valide (ex. : pseudo@domaine.fr)",
"pattern_firstname": "Doit être un prénom valide",
@@ -264,7 +264,7 @@
"certmanager_cert_renew_success": "Renouvellement avec succès d’un certificat Let’s Encrypt pour le domaine {domain:s} !",
"certmanager_old_letsencrypt_app_detected": "\nYunoHost a détecté que l’application « letsencrypt » est installé, ce qui est en conflit avec les nouvelles fonctionnalités de gestion intégrée de certificats dans YunoHost. Si vous souhaitez utiliser ces nouvelles fonctionnalités intégrées, veuillez lancer les commandes suivantes pour migrer votre installation :\n\n yunohost app remove letsencrypt\n yunohost domain cert-install\n\nN.B. : cela tentera de réinstaller les certificats de tous les domaines avec un certificat Let's Encrypt ou ceux auto-signés",
"certmanager_cert_signing_failed": "La signature du nouveau certificat a échoué",
- "certmanager_no_cert_file": "Impossible de lire le fichier de/du certificat pour le domaine {domain:s} (fichier : {file:s})",
+ "certmanager_no_cert_file": "Impossible de lire le fichier du certificat pour le domaine {domain:s} (fichier : {file:s})",
"certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration Nginx {filepath:s} est en conflit et doit être préalablement retiré",
"certmanager_hit_rate_limit": "Trop de certificats ont déjà été émis récemment pour ce même ensemble de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails sur les ratios et limitations",
"ldap_init_failed_to_create_admin": "L’initialisation de l'annuaire LDAP n’a pas réussi à créer l’utilisateur admin",
@@ -297,7 +297,7 @@
"app_location_unavailable": "Cette URL n’est pas disponible ou est en conflit avec une application existante :\n{apps:s}",
"app_already_up_to_date": "{app:s} est déjà à jour",
"invalid_url_format": "Format d’URL non valide",
- "global_settings_bad_choice_for_enum": "La valeur du paramètre {setting:s} est incorrecte. Reçu {received_type:s} alors que {expected_type:s} était attendu",
+ "global_settings_bad_choice_for_enum": "Valeur du paramètre {setting:s} incorrecte. Reçu : {received_type:s}, mais les valeurs possibles sont : {expected_type:s}",
"global_settings_bad_type_for_setting": "Le type du paramètre {setting:s} est incorrect. Reçu {received_type:s} alors que {expected_type:s} était attendu",
"global_settings_cant_open_settings": "Échec de l’ouverture du ficher de configurations car : {reason:s}",
"global_settings_cant_serialize_setings": "Échec de sérialisation des données de configurations, cause : {reason:s}",
@@ -315,7 +315,7 @@
"backup_abstract_method": "Cette méthode de sauvegarde n’a pas encore été implémentée",
"backup_applying_method_tar": "Création de l’archive tar de la sauvegarde …",
"backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder …",
- "backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans le référentiel/répertoire borg-backup …",
+ "backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans le répertoire borg-backup…",
"backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée '{method:s}' …",
"backup_archive_system_part_not_available": "La partie '{part:s}' du système n’est pas disponible dans cette sauvegarde",
"backup_archive_mount_failed": "Le montage de l’archive de sauvegarde a échoué",
@@ -347,7 +347,7 @@
"restore_system_part_failed": "Impossible de restaurer la partie '{part:s}' du système",
"backup_couldnt_bind": "Impossible de lier {src:s} avec {dest:s}.",
"domain_dns_conf_is_just_a_recommendation": "Cette page montre la configuration *recommandée*. Elle ne configure *pas* le DNS pour vous. Il est de votre responsabilité que de configurer votre zone DNS chez votre fournisseur/registrar DNS avec cette recommandation.",
- "domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost. Soit YunoHost n’est pas correctement connecté à internet, soit le serveur de dynette est en panne ou ne répond pas. Erreur : {error}",
+ "domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost. Soit YunoHost n’est pas correctement connecté à internet, soit le serveur de dynette est en panne. Erreur : {error}",
"migrations_backward": "Migration en arrière.",
"migrations_bad_value_for_target": "Nombre invalide pour le paramètre target, les numéros de migration sont 0 ou {}",
"migrations_cant_reach_migration_file": "Impossible d’accéder aux fichiers de migrations avec le chemin %s",
@@ -370,7 +370,7 @@
"dyndns_domain_not_provided": "Le fournisseur DynDNS {provider:s} ne peut pas fournir le domaine {domain:s}.",
"app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine {domain} car il est déjà utilisé par l'application '{other_app}'",
"app_upgrade_app_name": "Mise à jour de l’application {app} …",
- "backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives '{path:s}'. Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas, vous avez probablement oublié de monter ou de connecter votre disque dur ou votre clef USB.",
+ "backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives « {path:s} ». Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas, vous avez probablement oublié de monter ou de connecter votre disque dur ou votre clé USB.",
"migrate_tsig_end": "La migration à hmac-sha512 est terminée",
"migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué. Annulation des modifications. Erreur : {error_code} - {error}",
"migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine '{domain}', lancement de la migration vers hmac-sha512 qui est plus sécurisé",
@@ -380,7 +380,7 @@
"migrate_tsig_wait_4": "30 secondes …",
"migrate_tsig_not_needed": "Il ne semble pas que vous utilisez un domaine DynDNS, donc aucune migration n’est nécessaire !",
"app_checkurl_is_deprecated": "Packagers /!\\ 'app checkurl' est obsolète ! Utilisez 'app register-url' en remplacement !",
- "migration_description_0001_change_cert_group_to_sslcert": "Changement des permissions de groupe des certificats de 'metronome' à 'ssl-cert'",
+ "migration_description_0001_change_cert_group_to_sslcert": "Changement des permissions de groupe des certificats de « metronome » à « ssl-cert »",
"migration_description_0002_migrate_to_tsig_sha256": "Amélioration de la sécurité de DynDNS TSIG en utilisant SHA512 au lieu de MD5",
"migration_description_0003_migrate_to_stretch": "Mise à niveau du système vers Debian Stretch et YunoHost 3.0",
"migration_0003_backward_impossible": "La migration Stretch n’est pas réversible.",
@@ -392,7 +392,7 @@
"migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du paquet YunoHost. La migration se terminera, mais la mise à jour réelle aura lieu immédiatement après. Une fois cette opération terminée, vous pourriez avoir à vous reconnecter à l’administration via le panel web.",
"migration_0003_not_jessie": "La distribution Debian actuelle n’est pas Jessie !",
"migration_0003_system_not_fully_up_to_date": "Votre système n’est pas complètement à jour. Veuillez mener une mise à jour classique avant de lancer à migration à Stretch.",
- "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Jessie !? Pour en savoir plus et investiguer sur ce problème, veuillez regarder les journaux {log}:s .",
+ "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Jessie !? Pour investiguer sur problème, veuillez regarder les journaux {log}:s…",
"migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nEn outre, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence !",
"migration_0003_problematic_apps_warning": "Veuillez noter que des applications possiblement problématiques ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées comme 'fonctionnelles'/'working'. En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront après la mise à niveau : {problematic_apps}",
"migration_0003_modified_files": "Veuillez noter que les fichiers suivants ont été détectés comme modifiés manuellement et pourraient être écrasés à la fin de la mise à niveau : {manually_modified_files}",
@@ -426,7 +426,7 @@
"backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge php7, vos applications php pourraient ne pas être restaurées (reason: {error:s})",
"log_help_to_get_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de partager le journal historisé de cette opération en utilisant la commande 'yunohost log display {name} --share'",
"log_does_exists": "Il n’existe pas de journal historisé de l’opération ayant pour nom '{log}', utiliser 'yunohost log list pour voir tous les fichiers de journaux historisés disponibles'",
- "log_operation_unit_unclosed_properly": "L’opération ne s’est pas fermée/terminée correctement",
+ "log_operation_unit_unclosed_properly": "L’opération ne s’est pas terminée correctement",
"log_app_addaccess": "Ajouter l’accès à '{}'",
"log_app_removeaccess": "Enlever l’accès à '{}'",
"log_app_clearaccess": "Retirer tous les accès à '{}'",
@@ -462,7 +462,7 @@
"log_tools_shutdown": "Éteindre votre serveur",
"log_tools_reboot": "Redémarrer votre serveur",
"mail_unavailable": "Cette adresse de courriel est réservée et doit être automatiquement attribuée au tout premier utilisateur",
- "migration_description_0004_php5_to_php7_pools": "Reconfigurez le pool PHP pour utiliser PHP 7 au lieu de PHP 5",
+ "migration_description_0004_php5_to_php7_pools": "Reconfiguration des pools PHP pour utiliser PHP 7 au lieu de PHP 5",
"migration_description_0005_postgresql_9p4_to_9p6": "Migration des bases de données de PostgreSQL 9.4 vers PostgreSQL 9.6",
"migration_0005_postgresql_94_not_installed": "PostgreSQL n’a pas été installé sur votre système. Rien à faire !",
"migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 a été trouvé et installé, mais pas PostgreSQL 9.6 !? Quelque chose d’étrange a dû arriver à votre système :( …",
From 2d4785ec59099e56c566c70a6bed453d4028fda7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A9lanie=20Chauvel?=
Date: Sat, 23 Mar 2019 13:25:50 +0000
Subject: [PATCH 169/199] Translated using Weblate (French)
Currently translated at 99.8% (503 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
---
locales/fr.json | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/locales/fr.json b/locales/fr.json
index d8d3edbb1..1a8399454 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -309,7 +309,7 @@
"global_settings_setting_example_string": "Exemple d’option de type chaîne",
"global_settings_setting_example_enum": "Exemple d’option de type énumération",
"global_settings_unknown_type": "Situation inattendue : la configuration {setting:s} semble avoir le type {unknown_type:s} mais celui-ci n'est pas pris en charge par le système.",
- "global_settings_unknown_setting_from_settings_file": "Clef inconnue dans les paramètres : '{setting_key:s}', rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
+ "global_settings_unknown_setting_from_settings_file": "Clé inconnue dans les paramètres : '{setting_key:s}', rejet de cette clé et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
"service_conf_file_kept_back": "Le fichier de configuration '{conf}' devait être supprimé par le service {service} mais a été conservé.",
"backup_abstract_method": "Cette méthode de sauvegarde n’a pas encore été implémentée",
@@ -359,7 +359,7 @@
"migrations_no_migrations_to_run": "Aucune migration à lancer",
"migrations_show_currently_running_migration": "Application de la migration {number} {name} …",
"migrations_show_last_migration": "La dernière migration appliquée est {}",
- "migrations_skip_migration": "Ignorer et passer la migration {number} {name} …",
+ "migrations_skip_migration": "Ignorer et passer la migration {number} {name}…",
"server_shutdown": "Le serveur va éteindre",
"server_shutdown_confirm": "Le serveur va être éteint immédiatement, le voulez-vous vraiment ? [{answers:s}]",
"server_reboot": "Le serveur va redémarrer",
@@ -394,7 +394,7 @@
"migration_0003_system_not_fully_up_to_date": "Votre système n’est pas complètement à jour. Veuillez mener une mise à jour classique avant de lancer à migration à Stretch.",
"migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Jessie !? Pour investiguer sur problème, veuillez regarder les journaux {log}:s…",
"migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nEn outre, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence !",
- "migration_0003_problematic_apps_warning": "Veuillez noter que des applications possiblement problématiques ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées comme 'fonctionnelles'/'working'. En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront après la mise à niveau : {problematic_apps}",
+ "migration_0003_problematic_apps_warning": "Veuillez noter que des applications possiblement problématiques ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées comme « fonctionnelles ». En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront après la mise à niveau : {problematic_apps}",
"migration_0003_modified_files": "Veuillez noter que les fichiers suivants ont été détectés comme modifiés manuellement et pourraient être écrasés à la fin de la mise à niveau : {manually_modified_files}",
"migrations_list_conflict_pending_done": "Vous ne pouvez pas utiliser --previous et --done simultanément.",
"migrations_to_be_ran_manually": "La migration {number} {name} doit être lancée manuellement. Veuillez aller dans Outils > Migrations dans l’interface admin, ou lancer `yunohost tools migrations migrate`.",
@@ -473,7 +473,7 @@
"good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères — bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
- "migration_0006_disclaimer": "YunoHost s’attendra à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
+ "migration_0006_disclaimer": "YunoHost s’attendra désormais à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
"migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.",
"password_listed": "Ce mot de passe est l'un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d'un peu plus singulier.",
"password_too_simple_1": "Le mot de passe doit comporter au moins 8 caractères",
From 992e8e91b63daf30bc0b288e89c5542169f9b758 Mon Sep 17 00:00:00 2001
From: xaloc33
Date: Thu, 28 Mar 2019 23:25:26 +0000
Subject: [PATCH 170/199] Translated using Weblate (Catalan)
Currently translated at 33.5% (170 of 507 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ca/
---
locales/ca.json | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/locales/ca.json b/locales/ca.json
index dd01ddebb..9023b8c75 100644
--- a/locales/ca.json
+++ b/locales/ca.json
@@ -158,5 +158,15 @@
"diagnosis_monitor_disk_error": "No es poden monitorar els discs: {error}",
"diagnosis_monitor_network_error": "No es pot monitorar la xarxa: {error}",
"diagnosis_monitor_system_error": "No es pot monitorar el sistema: {error}",
- "diagnosis_no_apps": "No hi ha cap aplicació instal·lada"
+ "diagnosis_no_apps": "No hi ha cap aplicació instal·lada",
+ "admin_password_too_long": "Trieu una contrasenya de menys de 127 caràcters",
+ "dpkg_is_broken": "No es pot fer això en aquest instant perquè dpkg/apt (els gestors de paquets del sistema) sembla estar mal configurat... Podeu intentar solucionar-ho connectant-vos per ssh i executant \"sudo dpkg --configure -a\".",
+ "dnsmasq_isnt_installed": "sembla que dnsmasq no està instal·lat, executeu \"apt-get remove bind9 && apt-get install dnsmasq\"",
+ "domain_cannot_remove_main": "No es pot eliminar el domini principal. S'ha d'establir un nou domini primer",
+ "domain_cert_gen_failed": "No s'ha pogut generar el certificat",
+ "domain_created": "S'ha creat el domini",
+ "domain_creation_failed": "No s'ha pogut crear el domini",
+ "domain_deleted": "S'ha eliminat el domini",
+ "domain_deletion_failed": "No s'ha pogut eliminar el domini",
+ "domain_exists": "El domini ja existeix"
}
From b6cff68d73eafffbf985cd213cd2318b720823d2 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 2 Apr 2019 18:15:16 +0200
Subject: [PATCH 171/199] [fix] Do not miserably crash if status.json can't be
decoded
---
src/yunohost/app.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index 3d33ab8ae..38df51ea0 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -1773,12 +1773,18 @@ def _get_app_status(app_id, format_date=False):
raise YunohostError('app_unknown')
status = {}
+ regen_status = True
try:
with open(app_setting_path + '/status.json') as f:
status = json.loads(str(f.read()))
+ regen_status = False
except IOError:
logger.debug("status file not found for '%s'", app_id,
exc_info=1)
+ except Exception as e:
+ logger.warning("could not open or decode %s : %s ... regenerating.", app_setting_path + '/status.json', str(e))
+
+ if regen_status:
# Create app status
status = {
'installed_at': app_setting(app_id, 'install_time'),
From 889eb0caa158b9c951fd34909091f37d1ce06f55 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 2 Apr 2019 20:47:03 +0200
Subject: [PATCH 172/199] [fix] Fix the dbus interface to get info for
services, because this was not working when service is disabled
---
src/yunohost/service.py | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/src/yunohost/service.py b/src/yunohost/service.py
index 61274aaac..896090228 100644
--- a/src/yunohost/service.py
+++ b/src/yunohost/service.py
@@ -325,7 +325,7 @@ def service_status(names=[]):
result[name] = {
'status': str(status.get("SubState", "unknown")),
- 'loaded': "enabled" if str(status.get("LoadState", "unknown")) == "loaded" else str(status.get("LoadState", "unknown")),
+ 'loaded': str(status.get("UnitFileState", "unknown")),
'active': str(status.get("ActiveState", "unknown")),
'description': description,
'service_file_path': str(status.get("FragmentPath", "unknown")),
@@ -343,26 +343,25 @@ def service_status(names=[]):
def _get_service_information_from_systemd(service):
"this is the equivalent of 'systemctl status $service'"
import dbus
- from dbus.exceptions import DBusException
d = dbus.SystemBus()
systemd = d.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
manager = dbus.Interface(systemd, 'org.freedesktop.systemd1.Manager')
- try:
- service_path = manager.GetUnit(service + ".service")
- except DBusException as exception:
- if exception.get_dbus_name() == 'org.freedesktop.systemd1.NoSuchUnit':
- return None
- raise
-
- service_proxy = d.get_object('org.freedesktop.systemd1', service_path)
-
- # unit_proxy = dbus.Interface(service_proxy, 'org.freedesktop.systemd1.Unit',)
+ # c.f. https://zignar.net/2014/09/08/getting-started-with-dbus-python-systemd/
+ # Very interface, much intuitive, wow
+ service_unit = manager.LoadUnit(service + '.service')
+ service_proxy = d.get_object('org.freedesktop.systemd1', str(service_unit))
properties_interface = dbus.Interface(service_proxy, 'org.freedesktop.DBus.Properties')
- return properties_interface.GetAll('org.freedesktop.systemd1.Unit')
+ properties = properties_interface.GetAll('org.freedesktop.systemd1.Unit')
+
+ if properties.get("LoadState", "not-found") == "not-found":
+ # Service doesn't really exist
+ return None
+ else:
+ return properties
def service_log(name, number=50):
From e7ec6d968078207755572bbcb80df59e8454e90c Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 3 Apr 2019 02:21:31 +0200
Subject: [PATCH 173/199] Update changelog for 3.5.1
---
debian/changelog | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index 444d797e1..831b21ef5 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,22 @@
+yunohost (3.5.1) testing; urgency=low
+
+ - [fix] Fix the dbus interface to get info for services (#698)
+ - [mod] Use ask key for display_text instead and support i18n (#697)
+ - [fix] Rework tools update (#695)
+ - [enh] Nginx conf tweaks for theme (#689)
+ - [fix] Fix argument escaping in getopts (#685, #683)
+ - [enh] Support php versions in ynh_add_fpm_config (#674)
+ - [enh] Check that required services are up before running app install and upgrade (#670)
+ - [doc] Add min version for all helpers (#664)
+ - [enh] Add a setting to control compatibility/security tradeoff for nginx and ssh configurations (#640)
+ - [enh] Hooks to allow apps to extend the recommended DNS configuration (#517)
+ - Misc technical fixes / improvements (0bd781b, fad3edf, 1268872, 847ceca, 26e77b7, b6cff68)
+ - [i18n] Update translation for French, Catalan, Esperanto, Occitan
+
+ Thanks to all contributors: Aleks, Bram, Gabriel Corona, Jibec, Josue, Maniack C, Mélanie C., Quentí, Romuald du Song, ljf, ppr, Xaloc ! <3
+
+ -- Alexandre Aubin Wed, 03 Apr 2019 02:13:00 +0000
+
yunohost (3.5.0.2) testing; urgency=low
- [fix] Make sure that `ynh_system_user_delete` also deletes the group (#680)
From bf3ffc3e7d8d84c8e35a54fcdfb78b45c553dd8d Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 3 Apr 2019 12:22:47 +0200
Subject: [PATCH 174/199] [fix] service_status returns different type of data
if you one or multiple services
---
src/yunohost/app.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index 38df51ea0..97210d60c 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -2610,10 +2610,10 @@ def _check_services_status_for_app(services):
# (added by apps) and because those are the most popular
# services
service_filter = ["nginx", "php7.0-fpm", "mysql", "postfix"]
- services = [s for s in services if s in service_filter]
+ services = [str(s) for s in services if s in service_filter]
# List services currently down and raise an exception if any are found
- faulty_services = [s for s, infos in service_status(services).items() if infos["active"] != "active"]
+ faulty_services = [s for s in services if service_status(s)["active"] != "active"]
if faulty_services:
raise YunohostError('app_action_cannot_be_ran_because_required_services_down',
services=', '.join(faulty_services))
From 5c4bf1ed2905e0a69ca11ba0b13407e8493815b2 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 3 Apr 2019 13:02:15 +0200
Subject: [PATCH 175/199] [fix] nginx diagnosis when there's an error throwing
a huge useless traceback. Use Popen instead to display the real error
---
src/yunohost/tools.py | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index 635399801..0fb097805 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -720,12 +720,13 @@ def tools_diagnosis(auth, private=False):
}
# nginx -t
- try:
- diagnosis['nginx'] = check_output("nginx -t").strip().split("\n")
- except Exception as e:
- import traceback
- traceback.print_exc()
- logger.warning("Unable to check 'nginx -t', exception: %s" % e)
+ p = subprocess.Popen("nginx -t".split(),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ out, _ = p.communicate()
+ diagnosis["nginx"] = out.strip().split("\n")
+ if p.returncode != 0:
+ logger.error(out)
# Services status
services = service_status()
From 1f1173ad0c699904e79903362f0ca51978ba80f0 Mon Sep 17 00:00:00 2001
From: yalh76
Date: Wed, 3 Apr 2019 13:46:37 +0200
Subject: [PATCH 176/199] Use YNH_APP_INSTANCE_NAME instead of YNH_APP_ID
when using YNH_APP_ID, if you install two time the same application, when removing one of them, nodejs is uninstalled
---
data/helpers.d/nodejs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs
index b51bcd7c3..6833b7593 100644
--- a/data/helpers.d/nodejs
+++ b/data/helpers.d/nodejs
@@ -123,7 +123,7 @@ ynh_install_nodejs () {
fi
# Store the ID of this app and the version of node requested for it
- echo "$YNH_APP_ID:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version"
+ echo "$YNH_APP_INSTANCE_NAME:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version"
# Store nodejs_version into the config of this app
ynh_app_setting_set --app=$app --key=nodejs_version --value=$nodejs_version
@@ -147,7 +147,7 @@ ynh_remove_nodejs () {
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
# Remove the line for this app
- sed --in-place "/$YNH_APP_ID:$nodejs_version/d" "$n_install_dir/ynh_app_version"
+ sed --in-place "/$YNH_APP_INSTANCE_NAME:$nodejs_version/d" "$n_install_dir/ynh_app_version"
# If no other app uses this version of nodejs, remove it.
if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version"
From 69d2ad9a8ad8c9fbd95b7a0bb87b19656b12793d Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 3 Apr 2019 16:56:29 +0200
Subject: [PATCH 177/199] Fix loaded status for sysv services
---
src/yunohost/service.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/yunohost/service.py b/src/yunohost/service.py
index 896090228..b139c0b6d 100644
--- a/src/yunohost/service.py
+++ b/src/yunohost/service.py
@@ -31,6 +31,7 @@ import subprocess
import shutil
import hashlib
+from glob import glob
from difflib import unified_diff
from datetime import datetime
@@ -330,6 +331,12 @@ def service_status(names=[]):
'description': description,
'service_file_path': str(status.get("FragmentPath", "unknown")),
}
+
+ # Fun stuff™ : to obtain the enabled/disabled status for sysv services,
+ # gotta do this ... cf code of /lib/systemd/systemd-sysv-install
+ if result[name]["loaded"] == "generated":
+ result[name]["loaded"] = "enabled" if glob("/etc/rc[S5].d/S??"+name) else "disabled"
+
if "ActiveEnterTimestamp" in status:
result[name]['active_at'] = datetime.utcfromtimestamp(status["ActiveEnterTimestamp"] / 1000000)
else:
From c262313477aa0a7494f7b2bdcdeeef69ab85f807 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 3 Apr 2019 17:28:20 +0200
Subject: [PATCH 178/199] Update changelog for 3.5.1.1
---
debian/changelog | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index 831b21ef5..2d42719f6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+yunohost (3.5.1.1) testing; urgency=low
+
+ - [fix] enabled/disabled status for sysv services
+ - [fix] Nodejs helpers : use YNH_APP_INSTANCE_NAME instead of YNH_APP_ID (#700)
+ - [fix] nginx diagnosis when there's an error throwing a huge useless traceback. Use Popen instead to display the real error
+ - [fix] service_status returns different type of data if you ask for one or multiple services
+
+ -- Alexandre Aubin Wed, 03 Apr 2019 17:28:00 +0000
+
yunohost (3.5.1) testing; urgency=low
- [fix] Fix the dbus interface to get info for services (#698)
From a9761d356b8c787cbef6f0fb38025e75cb5e1ef0 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 8 Apr 2019 18:59:04 +0200
Subject: [PATCH 179/199] Update script to automatically generate helper
documentation
---
data/helpers.d/backend | 15 ++++++------
data/helpers.d/filesystem | 39 +++++++++++++-------------------
data/helpers.d/mysql | 4 ++--
data/helpers.d/network | 12 ++++++----
data/helpers.d/system | 2 +-
data/helpers.d/user | 11 ++++-----
doc/generate_helper_doc.py | 44 ++++++++++++++++++++++++++++--------
doc/helper_doc_template.html | 28 +++++++++++++++++++----
8 files changed, 96 insertions(+), 59 deletions(-)
diff --git a/data/helpers.d/backend b/data/helpers.d/backend
index 28c91e4f6..710e6299b 100644
--- a/data/helpers.d/backend
+++ b/data/helpers.d/backend
@@ -3,17 +3,17 @@
# Use logrotate to manage the logfile
#
# usage: ynh_use_logrotate [--logfile=/log/file] [--nonappend] [--specific_user=user/group]
-# | arg: -l, --logfile= - absolute path of logfile
-# | arg: -n, --nonappend - (Option) Replace the config file instead of appending this new config.
+# | arg: -l, --logfile - absolute path of logfile
+# | arg: -n, --nonappend - (optional) Replace the config file instead of appending this new config.
# | arg: -u, --specific_user : run logrotate as the specified user and group. If not specified logrotate is runned as root.
#
-# If no argument provided, a standard directory will be use. /var/log/${app}
-# You can provide a path with the directory only or with the logfile.
+# If no --logfile is provided, /var/log/${app} will be used as default.
+# logfile can be just a directory, or a full path to a logfile :
# /parentdir/logdir
# /parentdir/logdir/logfile.log
#
-# It's possible to use this helper several times, each config will be added to the same logrotate config file.
-# Unless you use the option --non-append
+# It's possible to use this helper multiple times, each config will be added to
+# the same logrotate config file. Unless you use the option --non-append
#
# Requires YunoHost version 2.6.4 or higher.
ynh_use_logrotate () {
@@ -175,8 +175,7 @@ ynh_remove_systemd_config () {
#
# usage: ynh_add_nginx_config "list of others variables to replace"
#
-# | arg: list of others variables to replace separeted by a space
-# | for example : 'path_2 port_2 ...'
+# | arg: list - (Optional) list of others variables to replace separated by spaces. For example : 'path_2 port_2 ...'
#
# This will use a template in ../conf/nginx.conf
# __PATH__ by $path_url
diff --git a/data/helpers.d/filesystem b/data/helpers.d/filesystem
index 6fb6347a6..07614d179 100644
--- a/data/helpers.d/filesystem
+++ b/data/helpers.d/filesystem
@@ -15,16 +15,13 @@ CAN_BIND=${CAN_BIND:-1}
# If DEST is ended by a slash it complete this path with the basename of SRC.
#
# usage: ynh_backup --src_path=src_path [--dest_path=dest_path] [--is_big] [--not_mandatory]
-# | arg: -s, --src_path - file or directory to bind or symlink or copy. it shouldn't be in
-# the backup dir.
-# | arg: -d, --dest_path - destination file or directory inside the
-# backup dir
+# | arg: -s, --src_path - file or directory to bind or symlink or copy. it shouldn't be in the backup dir.
+# | arg: -d, --dest_path - destination file or directory inside the backup dir
# | arg: -b, --is_big - Indicate data are big (mail, video, image ...)
# | arg: -m, --not_mandatory - Indicate that if the file is missing, the backup can ignore it.
# | arg: arg - Deprecated arg
#
-# example:
-# # Wordpress app context
+# Example in the context of a wordpress app
#
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf"
# # => This line will be added into CSV file
@@ -198,28 +195,25 @@ with open(sys.argv[1], 'r') as backup_file:
# Restore a file or a directory
#
# Use the registered path in backup_list by ynh_backup to restore the file at
-# the good place.
+# the right place.
#
# usage: ynh_restore_file --origin_path=origin_path [--dest_path=dest_path] [--not_mandatory]
-# | arg: -o, --origin_path - Path where was located the file or the directory before
-# to be backuped or relative path to $YNH_CWD where it is located in the backup archive
-# | arg: -d, --dest_path - Path where restore the file or the dir, if unspecified,
-# the destination will be ORIGIN_PATH or if the ORIGIN_PATH doesn't exist in
-# the archive, the destination will be searched into backup.csv
+# | arg: -o, --origin_path - Path where was located the file or the directory before to be backuped or relative path to $YNH_CWD where it is located in the backup archive
+# | arg: -d, --dest_path - Path where restore the file or the dir, if unspecified, the destination will be ORIGIN_PATH or if the ORIGIN_PATH doesn't exist in the archive, the destination will be searched into backup.csv
# | arg: -m, --not_mandatory - Indicate that if the file is missing, the restore process can ignore it.
#
+# examples:
+# ynh_restore_file "/etc/nginx/conf.d/$domain.d/$app.conf"
+# # You can also use relative paths:
+# ynh_restore_file "conf/nginx.conf"
+#
# If DEST_PATH already exists and is lighter than 500 Mo, a backup will be made in
# /home/yunohost.conf/backup/. Otherwise, the existing file is removed.
#
-# examples:
-# ynh_restore_file "/etc/nginx/conf.d/$domain.d/$app.conf"
-# # if apps/wordpress/etc/nginx/conf.d/$domain.d/$app.conf exists, restore it into
-# # /etc/nginx/conf.d/$domain.d/$app.conf
-# # if no, search a correspondance in the csv (eg: conf/nginx.conf) and restore it into
-# # /etc/nginx/conf.d/$domain.d/$app.conf
-#
-# # DON'T GIVE THE ARCHIVE PATH:
-# ynh_restore_file "conf/nginx.conf"
+# if apps/wordpress/etc/nginx/conf.d/$domain.d/$app.conf exists, restore it into
+# /etc/nginx/conf.d/$domain.d/$app.conf
+# if no, search for a match in the csv (eg: conf/nginx.conf) and restore it into
+# /etc/nginx/conf.d/$domain.d/$app.conf
#
# Requires YunoHost version 2.6.4 or higher.
ynh_restore_file () {
@@ -348,8 +342,7 @@ ynh_store_file_checksum () {
#
# usage: ynh_backup_if_checksum_is_different --file=file
# | arg: -f, --file - The file on which the checksum test will be perfomed.
-#
-# | ret: Return the name a the backup file, or nothing
+# | ret: the name of a backup file, or nothing
#
# Requires YunoHost version 2.6.4 or higher.
ynh_backup_if_checksum_is_different () {
diff --git a/data/helpers.d/mysql b/data/helpers.d/mysql
index 313b7a245..d7400db2d 100644
--- a/data/helpers.d/mysql
+++ b/data/helpers.d/mysql
@@ -186,7 +186,7 @@ ynh_mysql_drop_user() {
# usage: ynh_mysql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
# | arg: -u, --db_user - Owner of the database
# | arg: -n, --db_name - Name of the database
-# | arg: -p, --db_pwd - Password of the database. If not given, a password will be generated
+# | arg: -p, --db_pwd - Password of the database. If not provided, a password will be generated
#
# Requires YunoHost version 2.6.4 or higher.
ynh_mysql_setup_db () {
@@ -200,7 +200,7 @@ ynh_mysql_setup_db () {
ynh_handle_getopts_args "$@"
local new_db_pwd=$(ynh_string_random) # Generate a random password
- # If $db_pwd is not given, use new_db_pwd instead for db_pwd
+ # If $db_pwd is not provided, use new_db_pwd instead for db_pwd
db_pwd="${db_pwd:-$new_db_pwd}"
ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database
diff --git a/data/helpers.d/network b/data/helpers.d/network
index 8812f8f39..4dc080203 100644
--- a/data/helpers.d/network
+++ b/data/helpers.d/network
@@ -1,14 +1,16 @@
#!/bin/bash
# Normalize the url path syntax
+#
# Handle the slash at the beginning of path and its absence at ending
# Return a normalized url path
#
-# example: url_path=$(ynh_normalize_url_path $url_path)
-# ynh_normalize_url_path example -> /example
-# ynh_normalize_url_path /example -> /example
-# ynh_normalize_url_path /example/ -> /example
-# ynh_normalize_url_path / -> /
+# examples:
+# url_path=$(ynh_normalize_url_path $url_path)
+# ynh_normalize_url_path example # -> /example
+# ynh_normalize_url_path /example # -> /example
+# ynh_normalize_url_path /example/ # -> /example
+# ynh_normalize_url_path / # -> /
#
# usage: ynh_normalize_url_path --path_url=path_to_normalize
# | arg: -p, --path_url - URL path to normalize before using it
diff --git a/data/helpers.d/system b/data/helpers.d/system
index a491b19b5..757fdf93c 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -241,7 +241,7 @@ ynh_app_package_version () {
# - UPGRADE_APP if the upstream app version has changed
# - UPGRADE_PACKAGE if only the YunoHost package has changed
#
-## It stops the current script without error if the package is up-to-date
+# It stops the current script without error if the package is up-to-date
#
# This helper should be used to avoid an upgrade of an app, or the upstream part
# of it, when it's not needed
diff --git a/data/helpers.d/user b/data/helpers.d/user
index 83fa47aa8..9ee44515d 100644
--- a/data/helpers.d/user
+++ b/data/helpers.d/user
@@ -89,16 +89,15 @@ ynh_system_group_exists() {
# Create a system user
#
# examples:
-# - ynh_system_user_create --username=nextcloud -> creates a nextcloud user with
-# no home directory and /usr/sbin/nologin login shell (hence no login capability)
-# - ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_shell --> creates a
-# discourse user using /var/www/discourse as home directory and the default login shell
+# # Create a nextcloud user with no home directory and /usr/sbin/nologin login shell (hence no login capability)
+# ynh_system_user_create --username=nextcloud
+# # Create a discourse user using /var/www/discourse as home directory and the default login shell
+# ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_shell
#
# usage: ynh_system_user_create --username=user_name [--home_dir=home_dir] [--use_shell]
# | arg: -u, --username - Name of the system user that will be create
# | arg: -h, --home_dir - Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home
-# | arg: -s, --use_shell - Create a user using the default login shell if present.
-# If this argument is omitted, the user will be created with /usr/sbin/nologin shell
+# | arg: -s, --use_shell - Create a user using the default login shell if present. If this argument is omitted, the user will be created with /usr/sbin/nologin shell
#
# Requires YunoHost version 2.6.4 or higher.
ynh_system_user_create () {
diff --git a/doc/generate_helper_doc.py b/doc/generate_helper_doc.py
index 7d8c489b7..5b51dda02 100644
--- a/doc/generate_helper_doc.py
+++ b/doc/generate_helper_doc.py
@@ -4,7 +4,12 @@ import os
import glob
import datetime
-def render(data):
+def render(helpers):
+
+ data = { "helpers": helpers,
+ "date": datetime.datetime.now().strftime("%m/%d/%Y"),
+ "version": open("../debian/changelog").readlines()[0].split()[1].strip("()")
+ }
from jinja2 import Template
from ansi2html import Ansi2HTMLConverter
@@ -43,7 +48,7 @@ class Parser():
"code": [] }
for i, line in enumerate(self.file):
-
+
if line.startswith("#!/bin/bash"):
continue
@@ -103,7 +108,6 @@ class Parser():
b["usage"] = ""
b["args"] = []
b["ret"] = ""
- b["example"] = ""
subblocks = '\n'.join(b["comments"]).split("\n\n")
@@ -114,17 +118,29 @@ class Parser():
b["brief"] = subblock
continue
- elif subblock.startswith("example"):
+ elif subblock.startswith("example:"):
b["example"] = " ".join(subblock.split()[1:])
continue
+ elif subblock.startswith("examples:"):
+ b["examples"] = subblock.split("\n")[1:]
+ continue
+
elif subblock.startswith("usage"):
for line in subblock.split("\n"):
if line.startswith("| arg"):
- argname = line.split()[2]
- argdescr = " ".join(line.split()[4:])
- b["args"].append((argname, argdescr))
+ linesplit = line.split()
+ argname = linesplit[2]
+ # Detect that there's a long argument version (-f, --foo - Some description)
+ if argname.endswith(",") and linesplit[3].startswith("--"):
+ argname = argname.strip(",")
+ arglongname = linesplit[3]
+ argdescr = " ".join(linesplit[5:])
+ b["args"].append((argname, arglongname, argdescr))
+ else:
+ argdescr = " ".join(linesplit[4:])
+ b["args"].append((argname, argdescr))
elif line.startswith("| ret"):
b["ret"] = " ".join(line.split()[2:])
else:
@@ -136,9 +152,17 @@ class Parser():
elif subblock.startswith("| arg"):
for line in subblock.split("\n"):
if line.startswith("| arg"):
- argname = line.split()[2]
- argdescr = line.split()[4:]
- b["args"].append((argname, argdescr))
+ linesplit = line.split()
+ argname = linesplit[2]
+ # Detect that there's a long argument version (-f, --foo - Some description)
+ if argname.endswith(",") and linesplit[3].startswith("--"):
+ argname = argname.strip(",")
+ arglongname = linesplit[3]
+ argdescr = " ".join(linesplit[5:])
+ b["args"].append((argname, arglongname, argdescr))
+ else:
+ argdescr = " ".join(linesplit[4:])
+ b["args"].append((argname, argdescr))
continue
else:
diff --git a/doc/helper_doc_template.html b/doc/helper_doc_template.html
index 1fa1f68ad..92611c737 100644
--- a/doc/helper_doc_template.html
+++ b/doc/helper_doc_template.html
@@ -2,7 +2,7 @@
App helpers
-{% for category, helpers in data %}
+{% for category, helpers in data.helpers %}
{{ category }}
@@ -27,8 +27,12 @@
Arguments:
- {% for name, descr in h.args %}
-
{{ name }} : {{ descr }}
+ {% for infos in h.args %}
+ {% if infos|length == 2 %}
+
{{ infos[0] }} : {{ infos[1] }}
+ {% else %}
+
{{ infos[0] }}, {{ infos[1] }} : {{ infos[2] }}
+ {% endif %}
{% endfor %}
@@ -38,11 +42,25 @@
Returns: {{ h.ret }}
{% endif %}
- {% if h.example %}
+ {% if "example" in h.keys() %}
Example: {{ h.example }}
{% endif %}
+ {% if "examples" in h.keys() %}
+
+ Examples:
+ {% for example in h.examples %}
+ {% if not example.strip().startswith("# ") %}
+ {{ example }}
+ {% else %}
+ {{ example.strip("# ") }}
+ {% endif %}
+
+ {% endfor %}
+