mirror of
https://github.com/YunoHost/moulinette.git
synced 2024-09-03 20:06:31 +02:00
Compare commits
122 commits
debian/11.
...
dev
Author | SHA1 | Date | |
---|---|---|---|
|
8de98670e9 | ||
|
068d6d369a | ||
|
3c7f55c610 | ||
|
531c972bed | ||
|
7c378210fa | ||
|
497ea8a4af | ||
|
65d694280c | ||
|
dc1ce5a9ab | ||
|
663d80666a | ||
|
36c20d5582 | ||
|
95503ca2e6 | ||
|
96539ce5c7 | ||
|
578fb497e9 | ||
|
954d608a61 | ||
|
ac447a1f9d | ||
|
c63634f86f | ||
|
14bbff41ad | ||
|
291ed50843 | ||
|
5cb073bb75 | ||
|
8eb3ce3377 | ||
|
d1a7445773 | ||
|
41e170a214 | ||
|
dbcadf0c87 | ||
|
7f2563e65a | ||
|
e8b46f8c9b | ||
|
e196ed34c4 | ||
|
750aab64da | ||
|
1cac05b9fc | ||
|
f4712d9300 | ||
|
e96c380d29 | ||
|
d81b4578e9 | ||
|
0ffda1a0db | ||
|
b2b912e7b9 | ||
|
4a52f20417 | ||
|
cdd5ee6134 | ||
|
efc7d23738 | ||
|
2a2bb468fc | ||
|
f7a9678b59 | ||
|
50ce4c9b03 | ||
|
3bed227f6d | ||
|
45b1a92743 | ||
|
257e7095e5 | ||
|
4dfa2ee710 | ||
|
080d244f44 | ||
|
39113a8ed5 | ||
|
fe607a2ef1 | ||
|
d59f142019 | ||
|
c59b869286 | ||
|
8c38478d02 | ||
|
e8e206b482 | ||
|
21ecfbcd69 | ||
|
8bde8eee14 | ||
|
0ee77f922e | ||
|
97a24dbbce | ||
|
6e5429ce00 | ||
|
0ad9eac48c | ||
|
e00be08bee | ||
|
9316db6054 | ||
|
6e434cddc6 | ||
|
c698807f12 | ||
|
95f7e6804a | ||
|
c8193819c7 | ||
|
cadb449528 | ||
|
518e5ebb85 | ||
|
d09e1a2fab | ||
|
f1010fb8a3 | ||
|
7a46e1499d | ||
|
1b28bca0c0 | ||
|
d0089dbdf9 | ||
|
ecdc43a09a | ||
|
38d83520b5 | ||
|
1d3908c9a5 | ||
|
a69b276188 | ||
|
04a688a141 | ||
|
ed0cd88da9 | ||
|
b4e79bd278 | ||
|
5ec28b19c0 | ||
|
64a39cc595 | ||
|
e5fa7ab734 | ||
|
d66fd94f68 | ||
|
145fd9a91a | ||
|
0c71095db3 | ||
|
c06e1a91c9 | ||
|
d4769ec0a5 | ||
|
9078c881ea | ||
|
f6234577c4 | ||
|
6ec06b4ce3 | ||
|
d1e10e23d4 | ||
|
c5aeb1acad | ||
|
2373a7fa5e | ||
|
d1827d1a41 | ||
|
f1e7984fc9 | ||
|
1fb77feec3 | ||
|
52bbab7df1 | ||
|
aaf7f764e3 | ||
|
4d2694ef8d | ||
|
2539ea9c70 | ||
|
d7162b209a | ||
|
cabe9a728b | ||
|
4c03e16de9 | ||
|
9fc33eec1a | ||
|
95695e94d7 | ||
|
bc9b4a2ce2 | ||
|
55a09c57ac | ||
|
bbd2468e35 | ||
|
12c5482d6c | ||
|
ea90c056b7 | ||
|
c99439740f | ||
|
2195ed6f90 | ||
|
2d2eab4c30 | ||
|
9bc187d404 | ||
|
d0e65fdb46 | ||
|
01a4dc0942 | ||
|
baa00c0812 | ||
|
1e79e99cc8 | ||
|
ac0ac24996 | ||
|
7f4e8b394c | ||
|
aa06187284 | ||
|
676a19dc28 | ||
|
161c5d5c2b | ||
|
80873777c6 | ||
|
50b19a95c6 |
66 changed files with 377 additions and 412 deletions
19
.github/workflows/autoblack.yml
vendored
19
.github/workflows/autoblack.yml
vendored
|
@ -8,16 +8,23 @@ jobs:
|
|||
name: Check / auto apply black
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check files using the black formatter
|
||||
uses: rickstaa/action-black@v1
|
||||
id: action_black
|
||||
uses: psf/black@stable
|
||||
id: black
|
||||
with:
|
||||
black_args: "."
|
||||
options: "."
|
||||
continue-on-error: true
|
||||
- shell: pwsh
|
||||
id: check_files_changed
|
||||
run: |
|
||||
# Diff HEAD with the previous commit
|
||||
$diff = git diff
|
||||
$HasDiff = $diff.Length -gt 0
|
||||
Write-Host "::set-output name=files_changed::$HasDiff"
|
||||
- name: Create Pull Request
|
||||
if: steps.action_black.outputs.is_formatted == 'true'
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
if: steps.check_files_changed.outputs.files_changed == 'true'
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
title: "Format Python code with Black"
|
||||
|
|
4
.github/workflows/i18n.yml
vendored
4
.github/workflows/i18n.yml
vendored
|
@ -8,7 +8,7 @@ jobs:
|
|||
name: Autoreformat locale files
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Apply reformating scripts
|
||||
id: action_reformat
|
||||
run: |
|
||||
|
@ -18,7 +18,7 @@ jobs:
|
|||
git diff -w --exit-code
|
||||
- name: Create Pull Request
|
||||
if: ${{ failure() }}
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
title: "Reformat locale files"
|
||||
|
|
8
.github/workflows/tox.yml
vendored
8
.github/workflows/tox.yml
vendored
|
@ -14,9 +14,9 @@ jobs:
|
|||
matrix:
|
||||
python-version: [3.9]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install apt dependencies
|
||||
|
@ -34,9 +34,9 @@ jobs:
|
|||
matrix:
|
||||
python-version: [3.9]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install tox
|
||||
|
|
52
debian/changelog
vendored
52
debian/changelog
vendored
|
@ -1,3 +1,55 @@
|
|||
moulinette (11.2.1) stable; urgency=low
|
||||
|
||||
- repo chores: various black enhancements
|
||||
- [i18n] Translations updated for Arabic, Basque, Catalan, Chinese (Simplified), Czech, Dutch, English, Esperanto, French, Galician, German, Hindi, Indonesian, Italian, Japanese, Nepali, Norwegian Bokmål, Persian, Polish, Portuguese, Russian, Spanish, Swedish, Turkish, Ukrainian
|
||||
|
||||
Thanks to all contributors <3 ! (Alexandre Aubin, Francescc, José M, Metin Bektas, ppr, Psycojoker, rosbeef andino, Tagada, xabirequejo, xaloc33)
|
||||
|
||||
-- OniriCorpe <oniricorpe@yunohost.org> Sun, 19 May 2024 23:49:00 +0200
|
||||
|
||||
moulinette (11.2) stable; urgency=low
|
||||
|
||||
- [i18n] Translations updated for Japanese
|
||||
|
||||
Thanks to all contributors <3 ! (motcha)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 17 Jul 2023 16:32:34 +0200
|
||||
|
||||
moulinette (11.1.5) stable; urgency=low
|
||||
|
||||
- setup.py: fix version specifier in python_requires, python tooling not happy with * i guess (2373a7fa)
|
||||
- auth: prevent stupid issue where outdated cookie usage would trigger error 500 intead of 401, resulting in a ~bug after Yunohost self-upgrade and the webadmin is confused about the API not being up again (c06e1a91)
|
||||
- i18n: Translations updated for Chinese (Simplified), Indonesian, Japanese
|
||||
|
||||
Thanks to all contributors <3 ! (liimee, motcha, Neko Nekowazarashi, Poesty Li)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 10 Jul 2023 21:32:20 +0200
|
||||
|
||||
moulinette (11.1.4) stable; urgency=low
|
||||
|
||||
- Releasing as stable
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 01 Feb 2023 20:28:56 +0100
|
||||
|
||||
moulinette (11.1.2.1) testing; urgency=low
|
||||
|
||||
- Handle calling 'yunohost' with no args more gracefully (4c03e16d)
|
||||
- [i18n] Translations updated for Arabic
|
||||
|
||||
Thanks to all contributors <3 ! (ButterflyOfFire)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 30 Jan 2023 16:34:23 +0100
|
||||
|
||||
moulinette (11.1.2) testing; urgency=low
|
||||
|
||||
- legacy: Remove the 'global argument' mechanism ... we only use it for --version and it's just batshit overly complicated for what this achieves... (50b19a95, 80873777, 7f4e8b39)
|
||||
- Dont take lock for read/GET operations ([#327](https://github.com/yunohost/moulinette/pull/327))
|
||||
- [i18n] Translations updated for Arabic, Basque, Dutch
|
||||
|
||||
Thanks to all contributors <3 ! (André Koot, ButterflyOfFire, xabirequejo)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 06 Jan 2023 00:37:23 +0100
|
||||
|
||||
moulinette (11.1.0) testing; urgency=low
|
||||
|
||||
- Bump version for testing release
|
||||
|
|
|
@ -43,7 +43,7 @@ class Element:
|
|||
|
||||
def __repr__(self):
|
||||
"""Returns a basic state dump."""
|
||||
return 'Element' + str(self.index) + str(self.attributes)
|
||||
return "Element" + str(self.index) + str(self.attributes)
|
||||
|
||||
def add(self, line):
|
||||
"""Adds a line of input to the object.
|
||||
|
@ -57,10 +57,10 @@ class Element:
|
|||
"""
|
||||
|
||||
def _valid(line):
|
||||
return line and not line.startswith('#')
|
||||
return line and not line.startswith("#")
|
||||
|
||||
def _interesting(line):
|
||||
return line != 'objectClass: top'
|
||||
return line != "objectClass: top"
|
||||
|
||||
if self.is_valid() and not _valid(line):
|
||||
return True
|
||||
|
@ -70,11 +70,11 @@ class Element:
|
|||
|
||||
def is_valid(self):
|
||||
"""Indicates whether a valid entry has been read."""
|
||||
return len(self.attributes) != 0 and self.attributes[0].startswith('dn: ')
|
||||
return len(self.attributes) != 0 and self.attributes[0].startswith("dn: ")
|
||||
|
||||
def dn(self):
|
||||
"""Returns the DN for this entry."""
|
||||
if self.attributes[0].startswith('dn: '):
|
||||
if self.attributes[0].startswith("dn: "):
|
||||
return self.attributes[0][4:]
|
||||
else:
|
||||
return None
|
||||
|
@ -86,12 +86,12 @@ class Element:
|
|||
Element objects) and returns a string which declares a DOT edge, or an
|
||||
empty string, if no parent was found.
|
||||
"""
|
||||
dn_components = self.dn().split(',')
|
||||
dn_components = self.dn().split(",")
|
||||
for i in range(1, len(dn_components) + 1):
|
||||
parent = ','.join(dn_components[i:])
|
||||
parent = ",".join(dn_components[i:])
|
||||
if parent in dnmap:
|
||||
return ' n%d->n%d\n' % (dnmap[parent].index, self.index)
|
||||
return ''
|
||||
return " n%d->n%d\n" % (dnmap[parent].index, self.index)
|
||||
return ""
|
||||
|
||||
def dot(self, dnmap):
|
||||
"""Returns a text representation of the node and perhaps its parent edge.
|
||||
|
@ -99,6 +99,7 @@ class Element:
|
|||
Args:
|
||||
- dnmap: dictionary mapping dn names to Element objects
|
||||
"""
|
||||
|
||||
def _format(attributes):
|
||||
result = [TITLE_ENTRY_TEMPALTE % attributes[0]]
|
||||
|
||||
|
@ -107,7 +108,12 @@ class Element:
|
|||
|
||||
return result
|
||||
|
||||
return TABLE_TEMPLATE % (self.index, '\n '.join(_format(self.attributes)), self.edge(dnmap))
|
||||
return TABLE_TEMPLATE % (
|
||||
self.index,
|
||||
"\n ".join(_format(self.attributes)),
|
||||
self.edge(dnmap),
|
||||
)
|
||||
|
||||
|
||||
class Converter:
|
||||
"""An LDIF to DOT converter."""
|
||||
|
@ -144,7 +150,11 @@ class Converter:
|
|||
e = Element()
|
||||
if e.is_valid():
|
||||
self._append(e)
|
||||
return (BASE_TEMPLATE % (name, ''.join([e.dot(self.dnmap) for e in self.elements])))
|
||||
return BASE_TEMPLATE % (
|
||||
name,
|
||||
"".join([e.dot(self.dnmap) for e in self.elements]),
|
||||
)
|
||||
|
||||
|
||||
BASE_TEMPLATE = """\
|
||||
strict digraph "%s" {
|
||||
|
@ -191,13 +201,13 @@ ENTRY_TEMPALTE = """\
|
|||
"""
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 2:
|
||||
raise 'Expected at most one argument.'
|
||||
raise "Expected at most one argument."
|
||||
elif len(sys.argv) == 2:
|
||||
name = sys.argv[1]
|
||||
file = open(sys.argv[1], 'r')
|
||||
file = open(sys.argv[1], "r")
|
||||
else:
|
||||
name = '<stdin>'
|
||||
name = "<stdin>"
|
||||
file = sys.stdin
|
||||
print Converter().parse(file, name)
|
||||
print(Converter().parse(file, name))
|
||||
|
|
|
@ -28,18 +28,20 @@
|
|||
"cannot_open_file": "ليس بالإمكان فتح الملف {file} (السبب : {error})",
|
||||
"cannot_write_file": "لا يمكن الكتابة في الملف {file} (السبب : {error})",
|
||||
"unknown_error_reading_file": "طرأ هناك خطأ ما أثناء عملية قراءة الملف {file} (السبب: {error})",
|
||||
"corrupted_json": "قراءة json مُشوّهة مِن {ressource} (السبب : {error})",
|
||||
"corrupted_json": "قراءة ملف JSON مُشوّهة مِن {ressource} (السبب : {error})",
|
||||
"error_writing_file": "طرأ هناك خطأ أثناء الكتابة في الملف {file}: {error}",
|
||||
"error_removing": "خطأ أثناء عملية حذف {path}: {error}",
|
||||
"error_changing_file_permissions": "خطأ أثناء عملية تعديل التصريحات لـ {path}: {error}",
|
||||
"invalid_url": "خطأ في عنوان الرابط {url} (هل هذا الموقع موجود حقًا ؟)",
|
||||
"invalid_url": "فشل الاتصال بـ {url}… ربما تكون الخدمة معطلة ، أو أنك غير متصل بشكل صحيح بالإنترنت في IPv4 / IPv6.",
|
||||
"download_ssl_error": "خطأ في الاتصال الآمن عبر الـ SSL أثناء محاولة الربط بـ {url}",
|
||||
"download_timeout": "{url} استغرق مدة طويلة جدا للإستجابة، فتوقّف.",
|
||||
"download_unknown_error": "خطأ أثناء عملية تنزيل البيانات مِن {url} : {error}",
|
||||
"download_bad_status_code": "{url} أعاد رمز الحالة {code}",
|
||||
"corrupted_yaml": "قراءة مُشوّهة لنسق yaml مِن {ressource} (السبب : {error})",
|
||||
"corrupted_yaml": "قراءة مُشوّهة لملف YAML مِن {ressource} (السبب : {error})",
|
||||
"info": "معلومة:",
|
||||
"warn_the_user_about_waiting_lock_again": "جارٍ الانتظار…",
|
||||
"warn_the_user_that_lock_is_acquired": "لقد انتهى تنفيذ ذاك الأمر للتوّ ، جارٍ تنفيذ هذا الأمر",
|
||||
"warn_the_user_about_waiting_lock": "هناك أمر لـ YunoHost قيد التشغيل حاليا. في انتظار انتهاء تنفيذه قبل تشغيل التالي"
|
||||
}
|
||||
"warn_the_user_about_waiting_lock": "هناك أمر لـ YunoHost قيد التشغيل حاليا. في انتظار انتهاء تنفيذه قبل تشغيل التالي",
|
||||
"edit_text_question": "{}. تعديل هذا النص؟ [yN]: ",
|
||||
"corrupted_toml": "قراءة مُشوّهة لملف TOML مِن {ressource} (السبب : {error})"
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"argument_required": "Es requereix l'argument {argument}",
|
||||
"argument_required": "Es requereix l'argument «{argument}»",
|
||||
"authentication_required": "Es requereix autenticació",
|
||||
"confirm": "Confirmar{prompt}",
|
||||
"confirm": "Confirmar {prompt}",
|
||||
"deprecated_command": "{prog}{command}és obsolet i es desinstal·larà en el futur",
|
||||
"deprecated_command_alias": "{prog}{old}és obsolet i es desinstal·larà en el futur, utilitzeu {prog}{new}en el seu lloc",
|
||||
"error": "Error:",
|
||||
|
@ -33,7 +33,7 @@
|
|||
"error_writing_file": "Error al escriure el fitxer {file}: {error}",
|
||||
"error_removing": "Error al eliminar {path}: {error}",
|
||||
"error_changing_file_permissions": "Error al canviar els permisos per {path}: {error}",
|
||||
"invalid_url": "URL invàlid {url} (el lloc web existeix?)",
|
||||
"invalid_url": "No s'ha pogut connectar a {url}… pot ser que el servei estigui caigut, o que no hi hagi connexió a Internet amb IPv4/IPv6.",
|
||||
"download_ssl_error": "Error SSL al connectar amb {url}",
|
||||
"download_timeout": "{url} ha tardat massa en respondre, s'ha deixat d'esperar.",
|
||||
"download_unknown_error": "Error al baixar dades des de {url}: {error}",
|
||||
|
@ -42,5 +42,6 @@
|
|||
"corrupted_toml": "El fitxer TOML ha estat corromput en la lectura des de {ressource} (motiu: {error})",
|
||||
"warn_the_user_about_waiting_lock": "Hi ha una altra ordre de YunoHost en execució, s'executarà aquesta ordre un cop l'anterior hagi acabat",
|
||||
"warn_the_user_about_waiting_lock_again": "Encara en espera…",
|
||||
"warn_the_user_that_lock_is_acquired": "L'altra ordre tot just ha acabat, ara s'executarà aquesta ordre"
|
||||
"warn_the_user_that_lock_is_acquired": "L'altra ordre tot just ha acabat, ara s'executarà aquesta ordre",
|
||||
"edit_text_question": "{}. Edita aquest text ? [yN]: "
|
||||
}
|
|
@ -34,14 +34,14 @@
|
|||
"error_writing_file": "写入文件{file}失败:{error}",
|
||||
"error_removing": "删除路径{path}失败:{error}",
|
||||
"error_changing_file_permissions": "目录{path}权限修改失败:{error}",
|
||||
"invalid_url": "URL:{url}无效(site是否存在?)",
|
||||
"invalid_url": "{url} 连接失败… 可能是服务中断了,或者你没有正确连接到IPv4/IPv6的互联网。",
|
||||
"download_ssl_error": "连接{url}时发生SSL错误",
|
||||
"download_timeout": "{url}响应超时,放弃。",
|
||||
"download_unknown_error": "下载{url}失败:{error}",
|
||||
"download_bad_status_code": "{url}返回状态码:{code}",
|
||||
"warn_the_user_that_lock_is_acquired": "另一个命令刚刚完成,现在启动此命令",
|
||||
"warn_the_user_about_waiting_lock_again": "还在等...",
|
||||
"warn_the_user_about_waiting_lock_again": "仍在等待…",
|
||||
"warn_the_user_about_waiting_lock": "目前正在运行另一个YunoHost命令,我们在运行此命令之前等待它完成",
|
||||
"corrupted_toml": "从{ressource}读取的TOML已损坏(原因:{error})",
|
||||
"edit_text_question": "{}.编辑此文本?[yN]: "
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
"password": "Heslo",
|
||||
"logged_out": "Jste odhlášen/a",
|
||||
"warn_the_user_that_lock_is_acquired": "Předchozí operace dokončena, nyní spouštíme tuto",
|
||||
"warn_the_user_about_waiting_lock_again": "Stále čekáme...",
|
||||
"warn_the_user_about_waiting_lock_again": "Stále čekáme…",
|
||||
"warn_the_user_about_waiting_lock": "Jiná YunoHost operace právě probíhá, před spuštěním této čekáme na její dokončení",
|
||||
"download_bad_status_code": "{url} vrátil stavový kód {code}",
|
||||
"download_unknown_error": "Chyba při stahování dat z {url}: {error}",
|
||||
|
@ -44,4 +44,4 @@
|
|||
"authentication_required": "Vyžadováno ověření",
|
||||
"argument_required": "Je vyžadován argument '{argument}'",
|
||||
"edit_text_question": "{}. Upravit tento text? [yN]: "
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
{}
|
||||
{}
|
|
@ -32,16 +32,16 @@
|
|||
"cannot_open_file": "Datei {file} konnte nicht geöffnet werden (Ursache: {error})",
|
||||
"corrupted_yaml": "Beschädigtes YAML gelesen von {ressource} (reason: {error})",
|
||||
"warn_the_user_that_lock_is_acquired": "Der andere Befehl wurde gerade abgeschlossen, starte jetzt diesen Befehl",
|
||||
"warn_the_user_about_waiting_lock_again": "Immer noch wartend...",
|
||||
"warn_the_user_about_waiting_lock_again": "Immer noch wartend…",
|
||||
"warn_the_user_about_waiting_lock": "Ein anderer YunoHost Befehl läuft gerade, wir warten bis er fertig ist, bevor dieser laufen kann",
|
||||
"download_bad_status_code": "{url} lieferte folgende(n) Status Code(s) {code}",
|
||||
"download_unknown_error": "Fehler beim Herunterladen von Daten von {url}: {error}",
|
||||
"download_timeout": "{url} brauchte zu lange zum Antworten, hab aufgegeben.",
|
||||
"download_ssl_error": "SSL Fehler beim Verbinden zu {url}",
|
||||
"invalid_url": "Konnte keine Verbindung zu {url} herstellen... vielleicht ist der Dienst ausgefallen, oder Sie sind nicht richtig mit dem Internet in IPv4/IPv6 verbunden.",
|
||||
"invalid_url": "Konnte keine Verbindung zu {url} herstellen… vielleicht ist der Dienst ausgefallen, oder Sie sind nicht richtig mit dem Internet in IPv4/IPv6 verbunden.",
|
||||
"error_changing_file_permissions": "Fehler beim Ändern der Berechtigungen für {path}: {error}",
|
||||
"error_removing": "Fehler beim Entfernen {path}: {error}",
|
||||
"error_writing_file": "Fehler beim Schreiben von Datei {file}: {error}",
|
||||
"corrupted_toml": "Beschädigtes TOML gelesen von {ressource} (reason: {error})",
|
||||
"edit_text_question": "{}. Diesen Text bearbeiten? [yN]: "
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@
|
|||
"error_writing_file": "Error when writing file {file}: {error}",
|
||||
"error_removing": "Error when removing {path}: {error}",
|
||||
"error_changing_file_permissions": "Error when changing permissions for {path}: {error}",
|
||||
"invalid_url": "Failed to connect to {url} ... maybe the service is down, or you are not properly connected to the Internet in IPv4/IPv6.",
|
||||
"invalid_url": "Failed to connect to {url}... maybe the service is down, or you are not properly connected to the Internet in IPv4/IPv6.",
|
||||
"download_ssl_error": "SSL error when connecting to {url}",
|
||||
"download_timeout": "{url} took too long to answer, gave up.",
|
||||
"download_unknown_error": "Error when downloading data from {url}: {error}",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"password": "Pasvorto",
|
||||
"warn_the_user_that_lock_is_acquired": "La alia komando ĵus kompletigis, nun komencante ĉi tiun komandon",
|
||||
"warn_the_user_about_waiting_lock_again": "Ankoraŭ atendanta...",
|
||||
"warn_the_user_about_waiting_lock_again": "Ankoraŭ atendanta…",
|
||||
"warn_the_user_about_waiting_lock": "Alia komando de YunoHost funkcias ĝuste nun, ni atendas, ke ĝi finiĝos antaŭ ol funkcii ĉi tiu",
|
||||
"download_bad_status_code": "{url} redonita statuskodo {code}",
|
||||
"download_unknown_error": "Eraro dum elŝutado de datumoj de {url}: {error}",
|
||||
|
@ -16,7 +16,7 @@
|
|||
"corrupted_json": "Koruptita JSON legis de {ressource} (Kialo: {error})",
|
||||
"unknown_error_reading_file": "Nekonata eraro dum provi legi dosieron {file} (kialo: {error})",
|
||||
"cannot_write_file": "Ne povis skribi dosieron {file} (kialo: {error})",
|
||||
"cannot_open_file": "Ne povis malfermi dosieron {file: s} (kialo: {error: s})",
|
||||
"cannot_open_file": "Ne povis malfermi dosieron {file} (kialo: {error})",
|
||||
"websocket_request_expected": "Atendis ret-peto",
|
||||
"warning": "Averto:",
|
||||
"values_mismatch": "Valoroj ne kongruas",
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
"error_writing_file": "Error al escribir el archivo {file}: {error}",
|
||||
"error_removing": "Error al eliminar {path}: {error}",
|
||||
"error_changing_file_permissions": "Error al cambiar los permisos para {path}: {error}",
|
||||
"invalid_url": "URL inválida {url} (¿Existe este sitio?).",
|
||||
"invalid_url": "Imposible de conectarse a {url} (¿ la URL esta correcta, existe este sitio, o internet esta accesible?).",
|
||||
"download_ssl_error": "Error SSL al conectar con {url}",
|
||||
"download_timeout": "{url} tardó demasiado en responder, abandono.",
|
||||
"download_unknown_error": "Error al descargar datos desde {url} : {error}",
|
||||
|
@ -41,7 +41,7 @@
|
|||
"info": "Información:",
|
||||
"corrupted_toml": "Lectura corrupta de TOML desde {ressource} (motivo: {error})",
|
||||
"warn_the_user_that_lock_is_acquired": "La otra orden recién terminó, iniciando esta orden ahora",
|
||||
"warn_the_user_about_waiting_lock_again": "Aún esperando...",
|
||||
"warn_the_user_about_waiting_lock_again": "Aún esperando…",
|
||||
"warn_the_user_about_waiting_lock": "Otra orden de YunoHost se está ejecutando ahora, estamos esperando a que termine antes de ejecutar esta",
|
||||
"edit_text_question": "{}. Editar este texto ? [sN]: "
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"argument_required": "'{argument}' argumentua ezinbestekoa da",
|
||||
"logged_out": "Saioa itxita",
|
||||
"logged_out": "Saioa amaituta",
|
||||
"password": "Pasahitza",
|
||||
"authentication_required": "Autentifikazioa behar da",
|
||||
"confirm": "{prompt} baieztatu",
|
||||
|
@ -22,14 +22,14 @@
|
|||
"download_ssl_error": "SSL errorea {url}-(e)ra konektatzean",
|
||||
"corrupted_toml": "{ressource}-eko/go TOMLa kaltetuta dago (zergatia: {error})",
|
||||
"warn_the_user_about_waiting_lock": "YunoHosten beste komando bat ari da exekutatzen, horrek amaitu arte gaude zain",
|
||||
"warn_the_user_about_waiting_lock_again": "Zain…",
|
||||
"warn_the_user_about_waiting_lock_again": "Zain...",
|
||||
"folder_exists": "Direktorioa existitzen da dagoeneko: '{path}'",
|
||||
"instance_already_running": "YunoHosten eragiketa bat exekutatzen ari da dagoeneko. Mesedez, itxaron amaitu arte beste eragiketa bat abiarazi baino lehen.",
|
||||
"instance_already_running": "YunoHosten eragiketa bat exekutatzen ari da dagoeneko. Itxaron amaitu arte beste eragiketa bat abiarazi baino lehen.",
|
||||
"invalid_usage": "Erabilera okerra, idatzi --help aukerak ikusteko",
|
||||
"pattern_not_match": "Ez dator ereduarekin bat",
|
||||
"root_required": "Ezinbestekoa da 'root' izatea eragiketa hau exekutatzeko",
|
||||
"server_already_running": "Zerbitzari bat martxan dago dagoeneko ataka horretan",
|
||||
"unable_authenticate": "Ezinezkoa izan da autentifikatzea",
|
||||
"unable_authenticate": "Ezin da autentifikatu",
|
||||
"values_mismatch": "Balioak ez datoz bat",
|
||||
"warning": "Adi:",
|
||||
"cannot_open_file": "Ezinezkoa izan da {file} fitxategia irekitzea (zergatia: {error})",
|
||||
|
@ -42,6 +42,6 @@
|
|||
"error_writing_file": "Errorea {file} fitxategia idazterakoan: {error}",
|
||||
"error_removing": "Errorea {path} ezabatzerakoan: {error}",
|
||||
"download_bad_status_code": "{url} helbideak {code} egoera kodea agertu du",
|
||||
"invalid_url": "Ezinezkoa izan da {url}-(e)ra konektatzea… agian zerbitzua ez dago martxan, edo zeu ez zaude IPv4/IPv6 bidez ondo konektatuta internetera.",
|
||||
"invalid_url": "{url}-(e)ra konektatzeak huts egin du... agian zerbitzua ez dago martxan, edo ez zaude IPv4/IPv6 bidez ondo konektatuta internetera.",
|
||||
"download_timeout": "{url}(e)k denbora gehiegi behar izan du erantzuteko, bertan behera utzi du zerbitzariak."
|
||||
}
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
"argument_required": "استدلال '{argument}' ضروری است",
|
||||
"password": "کلمه عبور",
|
||||
"warn_the_user_that_lock_is_acquired": "فرمان دیگر به تازگی تکمیل شده است ، اکنون این دستور را شروع کنید",
|
||||
"warn_the_user_about_waiting_lock_again": "هنوز در انتظار...",
|
||||
"warn_the_user_about_waiting_lock_again": "هنوز در انتظار…",
|
||||
"warn_the_user_about_waiting_lock": "یکی دیگر از دستورات YunoHost در حال اجرا است ، ما منتظر هستیم تا قبل از اجرای این دستور به پایان برسد",
|
||||
"download_bad_status_code": "{url} کد وضعیّت بازگشتی {code}",
|
||||
"download_unknown_error": "خطا هنگام بارگیری داده ها از {url}: {error}",
|
||||
"download_timeout": "پاسخ {url} خیلی طول کشید ، منصرف شو.",
|
||||
"download_ssl_error": "خطای SSL هنگام اتصال به {url}",
|
||||
"invalid_url": "اتصال به {url} انجام نشد ... شاید سرویس خاموش باشد یا در IPv4/IPv6 به درستی به اینترنت متصل نشده باشید.",
|
||||
"invalid_url": "اتصال به {url} انجام نشد … شاید سرویس خاموش باشد یا در IPv4/IPv6 به درستی به اینترنت متصل نشده باشید.",
|
||||
"error_changing_file_permissions": "خطا هنگام تغییر مجوزهای {path}: {error}",
|
||||
"error_removing": "خطا هنگام حذف {path}: {error}",
|
||||
"error_writing_file": "خطا هنگام نوشتن فایل {file}: {error}",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"password": "Salasana",
|
||||
"logged_out": "Kirjauduttu ulos"
|
||||
}
|
||||
}
|
|
@ -4,11 +4,11 @@
|
|||
"confirm": "Confirmez {prompt}",
|
||||
"deprecated_command": "'{prog} {command}' est déprécié et sera bientôt supprimé",
|
||||
"deprecated_command_alias": "'{prog} {old}' est déprécié et sera bientôt supprimé, utilisez '{prog} {new}' à la place",
|
||||
"error": "Erreur :",
|
||||
"error": "Erreur :",
|
||||
"file_not_exist": "Le fichier '{path}' n'existe pas",
|
||||
"folder_exists": "Le dossier existe déjà : '{path}'",
|
||||
"folder_exists": "Le dossier existe déjà : '{path}'",
|
||||
"instance_already_running": "Une instance est déjà en cours d'exécution, merci d'attendre sa fin avant d'en lancer une autre.",
|
||||
"invalid_argument": "Argument '{argument}' incorrect : {error}",
|
||||
"invalid_argument": "Argument '{argument}' incorrect : {error}",
|
||||
"invalid_usage": "Utilisation erronée, utilisez --help pour accéder à l'aide",
|
||||
"logged_in": "Connecté",
|
||||
"logged_out": "Déconnecté",
|
||||
|
@ -16,32 +16,32 @@
|
|||
"operation_interrupted": "Opération interrompue",
|
||||
"password": "Mot de passe",
|
||||
"pattern_not_match": "Ne correspond pas au motif",
|
||||
"root_required": "Vous devez être super-utilisateur pour exécuter cette action",
|
||||
"root_required": "Vous devez avoir les droits d'administration pour exécuter cette action",
|
||||
"server_already_running": "Un serveur est déjà en cours d'exécution sur ce port",
|
||||
"success": "Succès !",
|
||||
"success": "Succès !",
|
||||
"unable_authenticate": "Impossible de vous authentifier",
|
||||
"unknown_group": "Le groupe '{group}' est inconnu",
|
||||
"unknown_user": "L'utilisateur '{user}' est inconnu",
|
||||
"unknown_user": "Le compte '{user}' est inconnu",
|
||||
"values_mismatch": "Les valeurs ne correspondent pas",
|
||||
"warning": "Attention :",
|
||||
"warning": "Attention :",
|
||||
"websocket_request_expected": "Une requête WebSocket est attendue",
|
||||
"cannot_open_file": "Impossible d'ouvrir le fichier {file} (raison : {error})",
|
||||
"cannot_write_file": "Ne peut pas écrire le fichier {file} (raison : {error})",
|
||||
"unknown_error_reading_file": "Erreur inconnue en essayant de lire le fichier {file} (raison :{error})",
|
||||
"corrupted_json": "Fichier JSON corrompu en lecture depuis {ressource} (raison : {error})",
|
||||
"error_writing_file": "Erreur en écrivant le fichier {file} : {error}",
|
||||
"error_removing": "Erreur lors de la suppression {path} : {error}",
|
||||
"error_changing_file_permissions": "Erreur lors de la modification des autorisations pour {path} : {error}",
|
||||
"invalid_url": "Impossible de se connecter à {url}... peut-être que le service est hors service/indisponible/interrompu, ou que vous n'êtes pas correctement connecté à Internet en IPv4/IPv6.",
|
||||
"cannot_open_file": "Impossible d'ouvrir le fichier {file} (raison : {error})",
|
||||
"cannot_write_file": "Ne peut pas écrire le fichier {file} (raison : {error})",
|
||||
"unknown_error_reading_file": "Erreur inconnue en essayant de lire le fichier {file} (raison :{error})",
|
||||
"corrupted_json": "Fichier JSON corrompu en lecture depuis {ressource} (raison : {error})",
|
||||
"error_writing_file": "Erreur en écrivant le fichier {file} : {error}",
|
||||
"error_removing": "Erreur lors de la suppression {path} : {error}",
|
||||
"error_changing_file_permissions": "Erreur lors de la modification des autorisations pour {path} : {error}",
|
||||
"invalid_url": "Impossible de se connecter à {url}... peut-être que le service est en panne ou que vous n'êtes pas correctement connecté à Internet en IPv4/IPv6.",
|
||||
"download_ssl_error": "Erreur SSL lors de la connexion à {url}",
|
||||
"download_timeout": "{url} a pris trop de temps pour répondre : abandon.",
|
||||
"download_unknown_error": "Erreur lors du téléchargement des données à partir de {url} : {error}",
|
||||
"download_timeout": "{url} a pris trop de temps pour répondre : abandon.",
|
||||
"download_unknown_error": "Erreur lors du téléchargement des données à partir de {url} : {error}",
|
||||
"download_bad_status_code": "{url} renvoie le code d'état {code}",
|
||||
"corrupted_yaml": "Fichier YAML corrompu en lecture depuis {ressource} (raison : {error})",
|
||||
"info": "Info :",
|
||||
"corrupted_toml": "Fichier TOML corrompu en lecture depuis {ressource} (raison : {error})",
|
||||
"corrupted_yaml": "Fichier YAML corrompu en lecture depuis {ressource} (raison : {error})",
|
||||
"info": "Info :",
|
||||
"corrupted_toml": "Fichier TOML corrompu en lecture depuis {ressource} (raison : {error})",
|
||||
"warn_the_user_about_waiting_lock": "Une autre commande YunoHost est actuellement en cours, nous attendons qu'elle se termine avant de démarrer celle là",
|
||||
"warn_the_user_about_waiting_lock_again": "Toujours en attente...",
|
||||
"warn_the_user_that_lock_is_acquired": "La commande précédente vient de se terminer, lancement de cette nouvelle commande",
|
||||
"edit_text_question": "{}. Modifier ce texte ? [yN] : "
|
||||
}
|
||||
"edit_text_question": "{}. Modifier ce texte ? [yN] : "
|
||||
}
|
||||
|
|
|
@ -26,13 +26,13 @@
|
|||
"not_logged_in": "Non iniciaches sesión",
|
||||
"logged_in": "Sesión iniciada",
|
||||
"warn_the_user_that_lock_is_acquired": "O outro comando rematou, agora executarase este",
|
||||
"warn_the_user_about_waiting_lock_again": "Agardando...",
|
||||
"warn_the_user_about_waiting_lock_again": "Agardando…",
|
||||
"warn_the_user_about_waiting_lock": "Estase executando outro comando de YunoHost neste intre, estamos agardando a que remate para executar este",
|
||||
"download_bad_status_code": "{url} devolveu o código de estado {code}",
|
||||
"download_unknown_error": "Erro ao descargar os datos desde {url}: {error}",
|
||||
"download_timeout": "{url} está tardando en responder, deixámolo.",
|
||||
"download_ssl_error": "Erro SSL ao conectar con {url}",
|
||||
"invalid_url": "Fallou a conexión con {url} ... pode que o servizo esté caído, ou que non teñas conexión a Internet con IPv4/IPv6.",
|
||||
"invalid_url": "Fallou a conexión con {url}... pode que o servizo estea caído, ou que non teñas conexión a Internet con IPv4/IPv6.",
|
||||
"error_changing_file_permissions": "Erro ao cambiar os permisos de {path}: {error}",
|
||||
"error_removing": "Erro ao eliminar {path}: {error}",
|
||||
"error_writing_file": "Erro ao escribir o ficheiro {file}: {error}",
|
||||
|
|
1
locales/he.json
Normal file
1
locales/he.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -1,19 +1,47 @@
|
|||
{
|
||||
"argument_required": "Argumen '{argument}' dibutuhkan",
|
||||
"authentication_required": "Otentikasi dibutuhkan",
|
||||
"authentication_required": "Autentikasi dibutuhkan",
|
||||
"deprecated_command": "'{prog} {command}' sudah usang dan akan dihapus nanti",
|
||||
"logged_out": "Berhasil keluar",
|
||||
"password": "Kata sandi",
|
||||
"deprecated_command_alias": "'{prog} {old}' sudah usang dan akan dihapus nanti, gunakan '{prog} {new}' saja",
|
||||
"deprecated_command_alias": "'{prog} {old}' sudah usang dan akan dihapus nanti, gunakan '{prog} {new}'",
|
||||
"info": "Informasi:",
|
||||
"instance_already_running": "Sudah ada operasi YunoHost yang sedang berjalan. Tunggu itu selesai sebelum menjalankan yang lain.",
|
||||
"instance_already_running": "Sudah ada tindakan YunoHost yang sedang berjalan. Tunggu itu selesai sebelum menjalankan yang lain.",
|
||||
"logged_in": "Berhasil masuk",
|
||||
"warning": "Peringatan:",
|
||||
"cannot_open_file": "Tidak dapat membuka berkas {file} (alasan: {error})",
|
||||
"error_removing": "Terjadi kesalahan ketika menghapus {path}: {error}",
|
||||
"error_removing": "Terjadi galat ketika menghapus {path}: {error}",
|
||||
"success": "Berhasil!",
|
||||
"warn_the_user_about_waiting_lock": "Perintah YunoHost lain sedang berjalan saat ini, kami sedang menunggu itu selesai sebelum menjalankan yang ini",
|
||||
"warn_the_user_about_waiting_lock_again": "Masih menunggu...",
|
||||
"unable_authenticate": "Tidak dapat mengotentikasi",
|
||||
"warn_the_user_that_lock_is_acquired": "Perintah yang tadi baru saja selesai, akan memulai perintah ini"
|
||||
"unable_authenticate": "Tidak dapat mengautentikasi",
|
||||
"warn_the_user_that_lock_is_acquired": "Perintah yang tadi baru saja selesai, akan memulai perintah ini",
|
||||
"server_already_running": "Sebuah peladen telah berjalan di porta tersebut",
|
||||
"unknown_group": "Kelompok '{group}' tidak diketahui",
|
||||
"unknown_user": "Pengguna '{user}' tidak diketahui",
|
||||
"values_mismatch": "Nnilai berbeda",
|
||||
"cannot_write_file": "Tidak dapat menyimpan berkas {file} (alasan: {error})",
|
||||
"unknown_error_reading_file": "Galat yang tidak diketahui ketika membaca berkas {file} (alasan: {error})",
|
||||
"invalid_url": "Gagal terhubung dengan {url}... mungkin layanan tersebut sedang turun, atau Anda tidak terhubung dengan benar ke internet di IPv4/IPv6.",
|
||||
"download_timeout": "{url} memakan waktu yang lama untuk menjawab, menyerah.",
|
||||
"download_unknown_error": "Galat ketika mengunduh data dari {url}: {error}",
|
||||
"download_bad_status_code": "{url} menjawab dengan kode status {code}",
|
||||
"confirm": "Konfirmasi {prompt}",
|
||||
"edit_text_question": "{}. Sunting teks ini ? [yN]: ",
|
||||
"error": "Galat:",
|
||||
"file_not_exist": "Berkas tidak ada: '{path}'",
|
||||
"folder_exists": "Berkas sudah ada: '{path}'",
|
||||
"invalid_argument": "Argumen tidak valid '{argument}': {error}",
|
||||
"invalid_usage": "Tidak valid, ikutkan --help untuk melihat bantuan",
|
||||
"not_logged_in": "Anda belum masuk",
|
||||
"operation_interrupted": "Tindakan terganggu",
|
||||
"error_writing_file": "Galat ketika menyimpan berkas {file}: {error}",
|
||||
"error_changing_file_permissions": "Galat ketika mengubah izin untuk {path}: {error}",
|
||||
"download_ssl_error": "Galat SSL ketika menghubungi {url}",
|
||||
"pattern_not_match": "Tidak cocok dengan pola",
|
||||
"root_required": "Anda harus berada di root untuk melakukan tindakan ini",
|
||||
"corrupted_yaml": "Pembacaan rusak untuk YAML {ressource} (alasan: {error})",
|
||||
"corrupted_toml": "Pembacaan rusak untuk TOML {ressource} (alasan: {error})",
|
||||
"corrupted_json": "Pembacaan rusak untuk JSON {ressource} (alasan: {error})",
|
||||
"websocket_request_expected": "Mengharapkan permintaan WebSocket"
|
||||
}
|
||||
|
|
|
@ -33,15 +33,15 @@
|
|||
"error_writing_file": "Errore durante la scrittura del file {file}: {error}",
|
||||
"error_removing": "Errore durante la rimozione {path}: {error}",
|
||||
"error_changing_file_permissions": "Errore durante il cambio di permessi per {path}: {error}",
|
||||
"invalid_url": "Fallita connessione a {url}... magari il servizio è down, o non sei connesso correttamente ad internet con IPv4/IPv6.",
|
||||
"invalid_url": "Fallita connessione a {url}… magari il servizio è down, o non sei connesso correttamente ad internet con IPv4/IPv6.",
|
||||
"download_ssl_error": "Errore SSL durante la connessione a {url}",
|
||||
"download_timeout": "{url} ci ha messo troppo a rispondere, abbandonato.",
|
||||
"download_unknown_error": "Errore durante il download di dati da {url} : {error}",
|
||||
"download_bad_status_code": "{url} ha restituito il codice di stato {code}",
|
||||
"info": "Info:",
|
||||
"warn_the_user_that_lock_is_acquired": "L'altro comando è appena completato, ora avvio questo comando",
|
||||
"warn_the_user_about_waiting_lock_again": "Sto ancora aspettando ...",
|
||||
"warn_the_user_about_waiting_lock_again": "Sto ancora aspettando…",
|
||||
"warn_the_user_about_waiting_lock": "Un altro comando YunoHost è in esecuzione in questo momento, stiamo aspettando che finisca prima di eseguire questo",
|
||||
"corrupted_toml": "TOML corrotto da {ressource} (motivo: {error})",
|
||||
"edit_text_question": "{}. Modificare il testo? [yN]: "
|
||||
}
|
||||
}
|
47
locales/ja.json
Normal file
47
locales/ja.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"logged_out": "ログアウトしました",
|
||||
"password": "パスワード",
|
||||
"argument_required": "引数 '{argument}' が必要です",
|
||||
"authentication_required": "認証が必要",
|
||||
"confirm": "{prompt}の確認",
|
||||
"deprecated_command": "'{prog} {command}' は非推奨であり、将来削除される予定です",
|
||||
"deprecated_command_alias": "'{prog} {old}' は非推奨であり、今後削除される予定です。代わりに '{prog} {new}' を使用してください",
|
||||
"edit_text_question": "{}.このテキストを編集しますか?[yN]: ",
|
||||
"error": "エラー:",
|
||||
"info": "インフォメーション:",
|
||||
"download_unknown_error": "{url}からデータをダウンロードする際のエラー:{error}",
|
||||
"download_bad_status_code": "{url}は状態コード {code} を返しました",
|
||||
"warn_the_user_about_waiting_lock": "別のYunoHostコマンドが現在実行されているため、完了するのを待っています",
|
||||
"warn_the_user_about_waiting_lock_again": "まだ待っています…",
|
||||
"warn_the_user_that_lock_is_acquired": "他のコマンドが完了しました。このコマンドが開始されました",
|
||||
"file_not_exist": "ファイルが存在しません: '{path}'",
|
||||
"folder_exists": "フォルダは既に存在します: '{path}'",
|
||||
"instance_already_running": "YunoHost 操作が既に実行されています。他の操作が完了するのを待ってください。",
|
||||
"invalid_argument": "無効な引数 '{argument}': {error}",
|
||||
"invalid_usage": "無効な使用法です。--help を渡してヘルプを表示します",
|
||||
"logged_in": "ログイン済み",
|
||||
"not_logged_in": "ログインしていません",
|
||||
"operation_interrupted": "操作が中断されました",
|
||||
"pattern_not_match": "パターンと一致しない",
|
||||
"root_required": "このアクションを実行するには、rootである必要があります",
|
||||
"server_already_running": "サーバーはそのポートで既に実行されています",
|
||||
"success": "成功!",
|
||||
"unable_authenticate": "認証できません",
|
||||
"unknown_group": "不明な '{group}' グループ",
|
||||
"unknown_user": "不明な '{user}' ユーザー",
|
||||
"values_mismatch": "値が一致しない",
|
||||
"warning": "警告:",
|
||||
"websocket_request_expected": "WebSocket 要求が必要です",
|
||||
"cannot_open_file": "ファイル{file}を開けませんでした(理由:{error})",
|
||||
"cannot_write_file": "ファイル {file}を書き込めませんでした (理由: {error})",
|
||||
"unknown_error_reading_file": "ファイル{file}を読み取ろうとしているときに不明なエラーが発生しました(理由:{error})",
|
||||
"corrupted_json": "{ressource}から読み取られたJSONは破損していました(理由:{error})",
|
||||
"corrupted_yaml": "破損した YAML が{ressource}から読み取られました (理由: {error})",
|
||||
"corrupted_toml": "破損した TOML が{ressource}から読み取られました (理由: {error})",
|
||||
"error_writing_file": "ファイル{file}書き込み時のエラー:{error}",
|
||||
"error_removing": "{path}を削除するときのエラー:{error}",
|
||||
"error_changing_file_permissions": "{path}のアクセス許可変更時のエラー: {error}",
|
||||
"invalid_url": "{url}に接続できませんでした…サービスがダウンしているか、IPv4 / IPv6でインターネットに正しく接続されていない可能性があります。",
|
||||
"download_ssl_error": "{url}への接続時のSSLエラー",
|
||||
"download_timeout": "{url}は応答に時間がかかりすぎたため、あきらめました。"
|
||||
}
|
|
@ -5,4 +5,4 @@
|
|||
"logged_in": "Taqqneḍ",
|
||||
"logged_out": "Yeffeɣ",
|
||||
"authentication_required": "Tlaq tuqqna"
|
||||
}
|
||||
}
|
1
locales/ko.json
Normal file
1
locales/ko.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
1
locales/lt.json
Normal file
1
locales/lt.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -7,7 +7,7 @@
|
|||
"unknown_user": "Ukjent '{user}' bruker",
|
||||
"unknown_group": "Ukjent '{group}' gruppe",
|
||||
"unable_authenticate": "Kunne ikke identitetsbekrefte",
|
||||
"success": "Vellykket.",
|
||||
"success": "Vellykket!",
|
||||
"operation_interrupted": "Operasjon forstyrret",
|
||||
"not_logged_in": "Du er ikke innlogget",
|
||||
"logged_in": "Innlogget",
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
"argument_required": "Argument {argument} is vereist",
|
||||
"authentication_required": "Aanmelding vereist",
|
||||
"confirm": "Bevestig {prompt}",
|
||||
"error": "Fout",
|
||||
"error": "Fout:",
|
||||
"file_not_exist": "Bestand bestaat niet: '{path}'",
|
||||
"folder_exists": "Deze map bestaat al: '{path}'",
|
||||
"instance_already_running": "Er is al een instantie actief, bedankt om te wachten tot deze afgesloten is alvorens een andere te starten.",
|
||||
"instance_already_running": "Er is al een bewerking bezig. Even geduld tot deze afgesloten is, alvorens een andere te starten.",
|
||||
"invalid_argument": "Ongeldig argument '{argument}': {error}",
|
||||
"invalid_usage": "Ongeldig gebruik, doe --help om de hulptekst te lezen",
|
||||
"logged_in": "Ingelogd",
|
||||
|
@ -28,20 +28,20 @@
|
|||
"cannot_open_file": "Niet mogelijk om bestand {file} te openen (reden: {error})",
|
||||
"cannot_write_file": "Niet gelukt om bestand {file} te schrijven (reden: {error})",
|
||||
"unknown_error_reading_file": "Ongekende fout tijdens het lezen van bestand {file} (cause:{error})",
|
||||
"corrupted_json": "Corrupte json gelezen van {ressource} (reden: {error})",
|
||||
"corrupted_json": "Corrupte JSON gelezen van {ressource} (reden: {error})",
|
||||
"error_writing_file": "Fout tijdens het schrijven van bestand {file}: {error}",
|
||||
"error_removing": "Fout tijdens het verwijderen van {path}: {error}",
|
||||
"error_changing_file_permissions": "Fout tijdens het veranderen van machtiging voor {path}: {error}",
|
||||
"invalid_url": "Ongeldige URL {url} (bestaat deze website?)",
|
||||
"invalid_url": "Kon niet verbinden met {url}… misschien is de dienst uit de lucht, of ben je niet goed verbonden via IPv4 of IPv6.",
|
||||
"download_ssl_error": "SSL fout gedurende verbinding met {url}",
|
||||
"download_timeout": "{url} neemt te veel tijd om te antwoorden, we geven het op.",
|
||||
"download_unknown_error": "Fout tijdens het downloaden van data van {url}: {error}",
|
||||
"download_bad_status_code": "{url} stuurt status code {code}",
|
||||
"warn_the_user_that_lock_is_acquired": "De andere opdracht is zojuist voltooid; nu wordt nu deze opdracht gestart",
|
||||
"warn_the_user_about_waiting_lock_again": "Nog steeds aan het wachten...",
|
||||
"warn_the_user_about_waiting_lock_again": "Nog steeds aan het wachten…",
|
||||
"warn_the_user_about_waiting_lock": "Een ander YunoHost commando wordt uitgevoerd, we wachten tot het gedaan is alovrens dit te starten",
|
||||
"corrupted_toml": "Ongeldige TOML werd gelezen van {ressource} (reason: {error})",
|
||||
"corrupted_yaml": "Ongeldig YAML bestand op {ressource} (reason: {error})",
|
||||
"corrupted_yaml": "Ongeldig YAML bestand op {ressource} (reden: {error})",
|
||||
"info": "Ter info:",
|
||||
"edit_text_question": "{}. Deze tekst bewerken ? [yN]: "
|
||||
}
|
||||
}
|
|
@ -44,4 +44,4 @@
|
|||
"warn_the_user_about_waiting_lock_again": "Encara en espèra…",
|
||||
"warn_the_user_that_lock_is_acquired": "l’autra comanda ven d’acabar, ara lançament d’aquesta comanda",
|
||||
"edit_text_question": "{}. Modificar aqueste tèxte ? [yN]: "
|
||||
}
|
||||
}
|
|
@ -2,13 +2,13 @@
|
|||
"logged_out": "Wylogowano",
|
||||
"password": "Hasło",
|
||||
"warn_the_user_that_lock_is_acquired": "Inne polecenie właśnie się zakończyło, teraz uruchamiam to polecenie",
|
||||
"warn_the_user_about_waiting_lock_again": "Wciąż czekam...",
|
||||
"warn_the_user_about_waiting_lock_again": "Wciąż czekam…",
|
||||
"warn_the_user_about_waiting_lock": "Kolejne polecenie YunoHost jest obecnie uruchomione, czekamy na jego zakończenie przed uruchomieniem tego",
|
||||
"download_bad_status_code": "{url} zwrócił kod stanu {code}",
|
||||
"download_unknown_error": "Błąd podczas pobierania danych z {url}: {error}",
|
||||
"download_timeout": "{url} potrzebował zbyt dużo czasu na odpowiedź, rezygnacja.",
|
||||
"download_ssl_error": "Błąd SSL podczas łączenia z {url}",
|
||||
"invalid_url": "Nie udało się połączyć z {url}... być może strona nie jest dostępna, lub nie jesteś prawidłowo połączony z Internetem po IPv4/IPv6.",
|
||||
"invalid_url": "Nie udało się połączyć z {url}… być może strona nie jest dostępna, lub nie jesteś prawidłowo połączony z Internetem po IPv4/IPv6.",
|
||||
"error_changing_file_permissions": "Błąd podczas zmiany uprawnień dla {path}: {error}",
|
||||
"error_removing": "Błąd podczas usuwania {path}: {error}",
|
||||
"error_writing_file": "Błąd podczas zapisywania pliku {file}: {error}",
|
||||
|
@ -44,4 +44,4 @@
|
|||
"authentication_required": "Wymagane uwierzytelnienie",
|
||||
"argument_required": "Argument „{argument}” jest wymagany",
|
||||
"edit_text_question": "{}. Zedytować ten tekst? [tN]: "
|
||||
}
|
||||
}
|
|
@ -39,9 +39,9 @@
|
|||
"corrupted_json": "JSON corrompido lido do {ressource} (motivo: {error})",
|
||||
"corrupted_yaml": "YAML corrompido lido do {ressource} (motivo: {error})",
|
||||
"warn_the_user_that_lock_is_acquired": "O outro comando acabou de concluir, agora iniciando este comando",
|
||||
"warn_the_user_about_waiting_lock_again": "Ainda esperando...",
|
||||
"warn_the_user_about_waiting_lock_again": "Ainda esperando…",
|
||||
"warn_the_user_about_waiting_lock": "Outro comando YunoHost está sendo executado agora, estamos aguardando o término antes de executar este",
|
||||
"corrupted_toml": "TOML corrompido lido em {ressource} (motivo: {error})",
|
||||
"info": "Informações:",
|
||||
"edit_text_question": "{}. Editar este texto ? [yN]: "
|
||||
}
|
||||
}
|
1
locales/pt_BR.json
Normal file
1
locales/pt_BR.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"argument_required": "Требуется'{argument}' аргумент",
|
||||
"argument_required": "Требуется аргумент «{argument}»",
|
||||
"authentication_required": "Требуется аутентификация",
|
||||
"confirm": "Подтвердить {prompt}",
|
||||
"deprecated_command": "'{prog} {command}' устарела и будет удалена",
|
||||
|
@ -10,7 +10,7 @@
|
|||
"invalid_argument": "Неправильный аргумент '{argument}': {error}",
|
||||
"logged_in": "Вы вошли",
|
||||
"logged_out": "Вы вышли из системы",
|
||||
"not_logged_in": "Вы не залогинились",
|
||||
"not_logged_in": "Вы не вошли в систему",
|
||||
"operation_interrupted": "Действие прервано",
|
||||
"password": "Пароль",
|
||||
"pattern_not_match": "Не соответствует образцу",
|
||||
|
@ -28,7 +28,7 @@
|
|||
"corrupted_yaml": "Повреждённой YAML получен от {ressource} (причина: {error})",
|
||||
"error_writing_file": "Ошибка при записи файла {file}: {error}",
|
||||
"error_removing": "Ошибка при удалении {path}: {error}",
|
||||
"invalid_url": "Не удалось подключиться к {url} ... возможно этот сервис недоступен или вы не подключены к Интернету через IPv4/IPv6.",
|
||||
"invalid_url": "Не удалось подключиться к {url}... возможно этот сервис недоступен или вы не подключены к Интернету через IPv4/IPv6.",
|
||||
"download_ssl_error": "Ошибка SSL при соединении с {url}",
|
||||
"download_timeout": "Превышено время ожидания ответа от {url}.",
|
||||
"download_unknown_error": "Ошибка при загрузке данных с {url} : {error}",
|
||||
|
|
|
@ -44,4 +44,4 @@
|
|||
"warn_the_user_about_waiting_lock": "Práve prebieha iná operácia YunoHost, pred spustením čakáme na jej dokončenie",
|
||||
"warn_the_user_about_waiting_lock_again": "Stále čakáme…",
|
||||
"warn_the_user_that_lock_is_acquired": "Predchádzajúca operácia bola dokončená, teraz spúšťame túto"
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
{}
|
||||
{}
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"warn_the_user_about_waiting_lock_again": "Väntar fortfarande …",
|
||||
"warn_the_user_about_waiting_lock_again": "Väntar fortfarande…",
|
||||
"download_bad_status_code": "{url} svarade med statuskod {code}",
|
||||
"download_timeout": "Gav upp eftersom {url} tog för lång tid på sig att svara.",
|
||||
"download_ssl_error": "Ett SSL-fel påträffades vid anslutning till {url}",
|
||||
|
|
|
@ -1 +1 @@
|
|||
{}
|
||||
{}
|
|
@ -19,13 +19,13 @@
|
|||
"warning": "Uyarı:",
|
||||
"websocket_request_expected": "WebSocket isteği gerekli",
|
||||
"warn_the_user_that_lock_is_acquired": "Diğer komut şimdi tamamlandı, şimdi bu komutu başlatıyor",
|
||||
"warn_the_user_about_waiting_lock_again": "Hala bekliyor...",
|
||||
"warn_the_user_about_waiting_lock_again": "Hala bekliyor…",
|
||||
"warn_the_user_about_waiting_lock": "Başka bir YunoHost komutu şu anda çalışıyor, bunu çalıştırmadan önce bitmesini bekliyoruz",
|
||||
"download_bad_status_code": "{url} döndürülen durum kodu {code}",
|
||||
"download_unknown_error": "{url} adresinden veri indirilirken hata oluştu: {error}",
|
||||
"download_timeout": "{url} yanıtlaması çok uzun sürdü, pes etti.",
|
||||
"download_ssl_error": "{url} ağına bağlanırken SSL hatası",
|
||||
"invalid_url": "{url} bağlanılamadı... URL çalışmıyor olabilir veya IPv4/IPv6 internete düzgün bir şekilde bağlı değilsiniz.",
|
||||
"invalid_url": "{url} bağlanılamadı… URL çalışmıyor olabilir veya IPv4/IPv6 internete düzgün bir şekilde bağlı değilsiniz.",
|
||||
"error_changing_file_permissions": "{path} için izinler değiştirilirken hata oluştu: {error}",
|
||||
"error_removing": "{path} kaldırılırken hata oluştu: {error}",
|
||||
"error_writing_file": "{file} dosyası yazılırken hata oluştu: {error}",
|
||||
|
@ -44,4 +44,4 @@
|
|||
"deprecated_command_alias": "'{prog} {old}' kullanımdan kaldırıldı ve gelecekte kaldırılacak, bunun yerine '{prog} {new}' kullanın",
|
||||
"deprecated_command": "'{prog} {command}' kullanımdan kaldırıldı ve gelecekte kaldırılacak",
|
||||
"edit_text_question": "{}. Bu metni düzenle ? [yN]: "
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"password": "Пароль",
|
||||
"logged_out": "Ви вийшли з системи",
|
||||
"invalid_url": "Помилка з'єднання із {url}... можливо, служба не працює, або ви неправильно під'єднані до Інтернету в IPv4/IPv6.",
|
||||
"invalid_url": "Помилка з'єднання із {url}… можливо, служба не працює, або ви неправильно під'єднані до Інтернету в IPv4/IPv6.",
|
||||
"warn_the_user_that_lock_is_acquired": "Інша команда щойно завершилася, тепер запускаємо цю команду",
|
||||
"warn_the_user_about_waiting_lock_again": "Досі очікуємо...",
|
||||
"warn_the_user_about_waiting_lock_again": "Досі очікуємо…",
|
||||
"warn_the_user_about_waiting_lock": "Зараз запускається ще одна команда YunoHost, ми чекаємо її завершення, перш ніж запустити цю",
|
||||
"download_bad_status_code": "{url} повернув код стану {code}",
|
||||
"download_unknown_error": "Помилка під час завантаження даних з {url}: {error}",
|
||||
|
|
37
maintenance/make_changelog.sh
Normal file
37
maintenance/make_changelog.sh
Normal file
|
@ -0,0 +1,37 @@
|
|||
VERSION="11.2.1"
|
||||
RELEASE="stable"
|
||||
REPO=$(basename $(git rev-parse --show-toplevel))
|
||||
REPO_URL=$(git remote get-url origin)
|
||||
ME=$(git config --get user.name)
|
||||
EMAIL=$(git config --get user.email)
|
||||
|
||||
LAST_RELEASE=$(git tag --list 'debian/11.*' --sort="v:refname" | tail -n 1)
|
||||
|
||||
echo "$REPO ($VERSION) $RELEASE; urgency=low"
|
||||
echo ""
|
||||
|
||||
git log $LAST_RELEASE.. -n 10000 --first-parent --pretty=tformat:' - %b%s (%h)' \
|
||||
| sed -E "s&Merge .*#([0-9]+).*\$& \([#\1]\(http://github.com/YunoHost/$REPO/pull/\1\)\)&g" \
|
||||
| sed -E "/Co-authored-by: .* <.*>/d" \
|
||||
| grep -v "Translations update from Weblate" \
|
||||
| tac
|
||||
|
||||
TRANSLATIONS=$(git log $LAST_RELEASE... -n 10000 --pretty=format:"%s" \
|
||||
| grep "Translated using Weblate" \
|
||||
| sed -E "s/Translated using Weblate \((.*)\)/\1/g" \
|
||||
| sort | uniq | tr '\n' ', ' | sed -e 's/,$//g' -e 's/,/, /g')
|
||||
[[ -z "$TRANSLATIONS" ]] || echo " - [i18n] Translations updated for $TRANSLATIONS"
|
||||
|
||||
echo ""
|
||||
CONTRIBUTORS=$(git log -n10 --pretty=format:'%Cred%h%Creset %C(bold blue)(%an) %Creset%Cgreen(%cr)%Creset - %s %C(yellow)%d%Creset' --abbrev-commit $LAST_RELEASE... -n 10000 --pretty=format:"%an" \
|
||||
| sort | uniq | grep -v "$ME" | grep -v 'yunohost-bot' | grep -vi 'weblate' \
|
||||
| tr '\n' ', ' | sed -e 's/,$//g' -e 's/,/, /g')
|
||||
[[ -z "$CONTRIBUTORS" ]] || echo " Thanks to all contributors <3 ! ($CONTRIBUTORS)"
|
||||
echo ""
|
||||
echo " -- $ME <$EMAIL> $(date -R)"
|
||||
echo ""
|
||||
|
||||
|
||||
|
||||
# PR links can be converted to regular texts using : sed -E 's@\[(#[0-9]*)\]\([^ )]*\)@\1@g'
|
||||
# Or readded with sed -E 's@#([0-9]*)@[YunoHost#\1](https://github.com/yunohost/yunohost/pull/\1)@g' | sed -E 's@\((\w+)\)@([YunoHost/\1](https://github.com/yunohost/yunohost/commit/\1))@g'
|
|
@ -39,7 +39,6 @@ class classproperty:
|
|||
|
||||
|
||||
class Moulinette:
|
||||
|
||||
_interface = None
|
||||
|
||||
def prompt(*args, **kwargs):
|
||||
|
|
|
@ -18,7 +18,7 @@ from moulinette.core import (
|
|||
MoulinetteLock,
|
||||
MoulinetteValidationError,
|
||||
)
|
||||
from moulinette.interfaces import BaseActionsMapParser, TO_RETURN_PROP
|
||||
from moulinette.interfaces import BaseActionsMapParser
|
||||
from moulinette.utils.log import start_action_logging
|
||||
from moulinette.utils.filesystem import read_yaml
|
||||
|
||||
|
@ -107,7 +107,6 @@ class CommentParameter(_ExtraParameter):
|
|||
|
||||
|
||||
class AskParameter(_ExtraParameter):
|
||||
|
||||
"""
|
||||
Ask for the argument value if possible and needed.
|
||||
|
||||
|
@ -146,7 +145,6 @@ class AskParameter(_ExtraParameter):
|
|||
|
||||
|
||||
class PasswordParameter(AskParameter):
|
||||
|
||||
"""
|
||||
Ask for the password argument value if possible and needed.
|
||||
|
||||
|
@ -169,7 +167,6 @@ class PasswordParameter(AskParameter):
|
|||
|
||||
|
||||
class PatternParameter(_ExtraParameter):
|
||||
|
||||
"""
|
||||
Check if the argument value match a pattern.
|
||||
|
||||
|
@ -222,7 +219,6 @@ class PatternParameter(_ExtraParameter):
|
|||
|
||||
|
||||
class RequiredParameter(_ExtraParameter):
|
||||
|
||||
"""
|
||||
Check if a required argument is defined or not.
|
||||
|
||||
|
@ -262,7 +258,6 @@ extraparameters_list = [
|
|||
|
||||
|
||||
class ExtraArgumentParser:
|
||||
|
||||
"""
|
||||
Argument validator and parser for the extra parameters.
|
||||
|
||||
|
@ -374,7 +369,6 @@ class ExtraArgumentParser:
|
|||
|
||||
|
||||
class ActionsMap:
|
||||
|
||||
"""Validate and process actions defined into an actions map
|
||||
|
||||
The actions map defines the features - and their usage - of an
|
||||
|
@ -392,7 +386,6 @@ class ActionsMap:
|
|||
"""
|
||||
|
||||
def __init__(self, actionsmap_yml, top_parser, load_only_category=None):
|
||||
|
||||
assert isinstance(top_parser, BaseActionsMapParser), (
|
||||
"Invalid parser class '%s'" % top_parser.__class__.__name__
|
||||
)
|
||||
|
@ -408,7 +401,6 @@ class ActionsMap:
|
|||
actionsmap_pkl = f"{actionsmap_yml_dir}/.{actionsmap_yml_file}.{actionsmap_yml_stat.st_size}-{actionsmap_yml_stat.st_mtime}.pkl"
|
||||
|
||||
def generate_cache():
|
||||
|
||||
logger.debug("generating cache for actions map")
|
||||
|
||||
# Read actions map from yaml file
|
||||
|
@ -464,7 +456,6 @@ class ActionsMap:
|
|||
|
||||
@cache
|
||||
def get_authenticator(self, auth_method):
|
||||
|
||||
if auth_method == "default":
|
||||
auth_method = self.default_authentication
|
||||
|
||||
|
@ -484,7 +475,6 @@ class ActionsMap:
|
|||
return mod.Authenticator()
|
||||
|
||||
def check_authentication_if_required(self, *args, **kwargs):
|
||||
|
||||
auth_method = self.parser.auth_method(*args, **kwargs)
|
||||
|
||||
if auth_method is None:
|
||||
|
@ -515,9 +505,7 @@ class ActionsMap:
|
|||
tid = arguments.pop("_tid")
|
||||
arguments = self.extraparser.parse_args(tid, arguments)
|
||||
|
||||
# Return immediately if a value is defined
|
||||
if TO_RETURN_PROP in arguments:
|
||||
return arguments.get(TO_RETURN_PROP)
|
||||
want_to_take_lock = self.parser.want_to_take_lock(args, **kwargs)
|
||||
|
||||
# Retrieve action information
|
||||
if len(tid) == 4:
|
||||
|
@ -541,7 +529,7 @@ class ActionsMap:
|
|||
full_action_name = "{}.{}.{}".format(namespace, category, action)
|
||||
|
||||
# Lock the moulinette for the namespace
|
||||
with MoulinetteLock(namespace, timeout, self.enable_lock):
|
||||
with MoulinetteLock(namespace, timeout, self.enable_lock and want_to_take_lock):
|
||||
start = time()
|
||||
try:
|
||||
mod = __import__(
|
||||
|
@ -626,13 +614,9 @@ class ActionsMap:
|
|||
self.enable_lock = _global.get("lock", True)
|
||||
self.default_authentication = _global["authentication"][interface_type]
|
||||
|
||||
if top_parser.has_global_parser():
|
||||
top_parser.add_global_arguments(_global["arguments"])
|
||||
|
||||
# category_name is stuff like "user", "domain", "hooks"...
|
||||
# category_values is the values of this category (like actions)
|
||||
for category_name, category_values in actionsmap.items():
|
||||
|
||||
actions = category_values.pop("actions", {})
|
||||
subcategories = category_values.pop("subcategories", {})
|
||||
|
||||
|
@ -669,10 +653,17 @@ class ActionsMap:
|
|||
if interface_type in authentication:
|
||||
action_parser.authentication = authentication[interface_type]
|
||||
|
||||
# Disable the locking mechanism for all actions that are 'GET' actions on the api
|
||||
routes = action_options.get("api")
|
||||
routes = [routes] if isinstance(routes, str) else routes
|
||||
if routes and all(route.startswith("GET ") for route in routes):
|
||||
action_parser.want_to_take_lock = False
|
||||
else:
|
||||
action_parser.want_to_take_lock = True
|
||||
|
||||
# subcategory_name is like "cert" in "domain cert status"
|
||||
# subcategory_values is the values of this subcategory (like actions)
|
||||
for subcategory_name, subcategory_values in subcategories.items():
|
||||
|
||||
actions = subcategory_values.pop("actions")
|
||||
|
||||
# Get subcategory parser
|
||||
|
@ -712,5 +703,13 @@ class ActionsMap:
|
|||
if interface_type in authentication:
|
||||
action_parser.authentication = authentication[interface_type]
|
||||
|
||||
# Disable the locking mechanism for all actions that are 'GET' actions on the api
|
||||
routes = action_options.get("api")
|
||||
routes = [routes] if isinstance(routes, str) else routes
|
||||
if routes and all(route.startswith("GET ") for route in routes):
|
||||
action_parser.want_to_take_lock = False
|
||||
else:
|
||||
action_parser.want_to_take_lock = True
|
||||
|
||||
logger.debug("building parser took %.3fs", time() - start)
|
||||
return top_parser
|
||||
|
|
|
@ -11,7 +11,6 @@ logger = logging.getLogger("moulinette.authenticator")
|
|||
|
||||
|
||||
class BaseAuthenticator:
|
||||
|
||||
"""Authenticator base representation
|
||||
|
||||
Each authenticators must implement an Authenticator class derived
|
||||
|
@ -29,7 +28,6 @@ class BaseAuthenticator:
|
|||
# Each authenticator classes must implement these methods.
|
||||
|
||||
def authenticate_credentials(self, credentials):
|
||||
|
||||
try:
|
||||
# Attempt to authenticate
|
||||
auth_info = self._authenticate_credentials(credentials) or {}
|
||||
|
|
|
@ -18,7 +18,6 @@ def during_unittests_run():
|
|||
|
||||
|
||||
class Translator:
|
||||
|
||||
"""Internationalization class
|
||||
|
||||
Provide an internationalization mechanism based on JSON files to
|
||||
|
@ -116,7 +115,6 @@ class Translator:
|
|||
self.default_locale != self.locale
|
||||
and key in self._translations.get(self.default_locale, {})
|
||||
):
|
||||
|
||||
try:
|
||||
return self._translations[self.default_locale][key].format(
|
||||
*args, **kwargs
|
||||
|
@ -174,7 +172,6 @@ class Translator:
|
|||
|
||||
|
||||
class Moulinette18n:
|
||||
|
||||
"""Internationalization service for the moulinette
|
||||
|
||||
Manage internationalization and access to the proper keys translation
|
||||
|
@ -246,7 +243,6 @@ class Moulinette18n:
|
|||
|
||||
|
||||
class MoulinetteError(Exception):
|
||||
|
||||
http_code = 500
|
||||
|
||||
"""Moulinette base exception"""
|
||||
|
@ -264,17 +260,14 @@ class MoulinetteError(Exception):
|
|||
|
||||
|
||||
class MoulinetteValidationError(MoulinetteError):
|
||||
|
||||
http_code = 400
|
||||
|
||||
|
||||
class MoulinetteAuthenticationError(MoulinetteError):
|
||||
|
||||
http_code = 401
|
||||
|
||||
|
||||
class MoulinetteLock:
|
||||
|
||||
"""Locker for a moulinette instance
|
||||
|
||||
It provides a lock mechanism for a given moulinette instance. It can
|
||||
|
@ -321,7 +314,6 @@ class MoulinetteLock:
|
|||
logger.debug("acquiring lock...")
|
||||
|
||||
while True:
|
||||
|
||||
lock_pids = self._lock_PIDs()
|
||||
|
||||
if self._is_son_of(lock_pids):
|
||||
|
@ -389,7 +381,6 @@ class MoulinetteLock:
|
|||
raise MoulinetteError("root_required")
|
||||
|
||||
def _lock_PIDs(self):
|
||||
|
||||
if not os.path.isfile(self._lockfile):
|
||||
return []
|
||||
|
||||
|
|
|
@ -5,25 +5,19 @@ import logging
|
|||
import argparse
|
||||
import copy
|
||||
import datetime
|
||||
from collections import deque, OrderedDict
|
||||
from collections import OrderedDict
|
||||
from json.encoder import JSONEncoder
|
||||
from typing import Optional
|
||||
|
||||
from moulinette import m18n
|
||||
from moulinette.core import MoulinetteError
|
||||
|
||||
logger = logging.getLogger("moulinette.interface")
|
||||
|
||||
# FIXME : are these even used for anything useful ...
|
||||
TO_RETURN_PROP = "_to_return"
|
||||
CALLBACKS_PROP = "_callbacks"
|
||||
|
||||
|
||||
# Base Class -----------------------------------------------------------
|
||||
|
||||
|
||||
class BaseActionsMapParser:
|
||||
|
||||
"""Actions map's base Parser
|
||||
|
||||
Each interfaces must implement an ActionsMapParser class derived
|
||||
|
@ -148,97 +142,11 @@ class BaseActionsMapParser:
|
|||
"derived class '%s' must override this method" % self.__class__.__name__
|
||||
)
|
||||
|
||||
# Arguments helpers
|
||||
|
||||
@staticmethod
|
||||
def prepare_action_namespace(tid, namespace=None):
|
||||
"""Prepare the namespace for a given action"""
|
||||
# Validate tid and namespace
|
||||
if not isinstance(tid, tuple) and (
|
||||
namespace is None or not hasattr(namespace, TO_RETURN_PROP)
|
||||
):
|
||||
raise MoulinetteError("invalid_usage")
|
||||
elif not tid:
|
||||
tid = "_global"
|
||||
|
||||
# Prepare namespace
|
||||
if namespace is None:
|
||||
namespace = argparse.Namespace()
|
||||
namespace._tid = tid
|
||||
|
||||
return namespace
|
||||
|
||||
|
||||
# Argument parser ------------------------------------------------------
|
||||
|
||||
|
||||
class _CallbackAction(argparse.Action):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
dest,
|
||||
nargs=0,
|
||||
callback={},
|
||||
default=argparse.SUPPRESS,
|
||||
help=None,
|
||||
):
|
||||
if not callback or "method" not in callback:
|
||||
raise ValueError("callback must be provided with at least " "a method key")
|
||||
super(_CallbackAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
nargs=nargs,
|
||||
default=default,
|
||||
help=help,
|
||||
)
|
||||
self.callback_method = callback.get("method")
|
||||
self.callback_kwargs = callback.get("kwargs", {})
|
||||
self.callback_return = callback.get("return", False)
|
||||
|
||||
@property
|
||||
def callback(self):
|
||||
if not hasattr(self, "_callback"):
|
||||
self._retrieve_callback()
|
||||
return self._callback
|
||||
|
||||
def _retrieve_callback(self):
|
||||
# Attempt to retrieve callback method
|
||||
mod_name, func_name = (self.callback_method).rsplit(".", 1)
|
||||
try:
|
||||
mod = __import__(mod_name, globals=globals(), level=0, fromlist=[func_name])
|
||||
func = getattr(mod, func_name)
|
||||
except (AttributeError, ImportError):
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
raise ValueError("unable to import method {}".format(self.callback_method))
|
||||
self._callback = func
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
parser.enqueue_callback(namespace, self, values)
|
||||
if self.callback_return:
|
||||
setattr(namespace, TO_RETURN_PROP, {})
|
||||
|
||||
def execute(self, namespace, values):
|
||||
try:
|
||||
# Execute callback and get returned value
|
||||
value = self.callback(namespace, values, **self.callback_kwargs)
|
||||
except Exception as e:
|
||||
error_message = "cannot get value from callback method " "'{}': {}".format(
|
||||
self.callback_method, e
|
||||
)
|
||||
logger.exception(error_message)
|
||||
raise MoulinetteError(error_message, raw_msg=True)
|
||||
else:
|
||||
if value:
|
||||
if self.callback_return:
|
||||
setattr(namespace, TO_RETURN_PROP, value)
|
||||
else:
|
||||
setattr(namespace, self.dest, value)
|
||||
|
||||
|
||||
class _ExtendedSubParsersAction(argparse._SubParsersAction):
|
||||
|
||||
"""Subparsers with extended properties for argparse
|
||||
|
||||
It provides the following additional properties at initialization,
|
||||
|
@ -319,35 +227,8 @@ class ExtendedArgumentParser(argparse.ArgumentParser):
|
|||
)
|
||||
|
||||
# Register additional actions
|
||||
self.register("action", "callback", _CallbackAction)
|
||||
self.register("action", "parsers", _ExtendedSubParsersAction)
|
||||
|
||||
def enqueue_callback(self, namespace, callback, values):
|
||||
queue = self._get_callbacks_queue(namespace)
|
||||
queue.append((callback, values))
|
||||
|
||||
def dequeue_callbacks(self, namespace):
|
||||
queue = self._get_callbacks_queue(namespace, False)
|
||||
for _i in range(len(queue)):
|
||||
c, v = queue.popleft()
|
||||
# FIXME: break dequeue if callback returns
|
||||
c.execute(namespace, v)
|
||||
try:
|
||||
delattr(namespace, CALLBACKS_PROP)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def _get_callbacks_queue(self, namespace, create=True):
|
||||
try:
|
||||
queue = getattr(namespace, CALLBACKS_PROP)
|
||||
except AttributeError:
|
||||
if create:
|
||||
queue = deque()
|
||||
setattr(namespace, CALLBACKS_PROP, queue)
|
||||
else:
|
||||
queue = list()
|
||||
return queue
|
||||
|
||||
def add_arguments(
|
||||
self, arguments, extraparser, format_arg_names=None, validate_extra=True
|
||||
):
|
||||
|
@ -400,11 +281,9 @@ class ExtendedArgumentParser(argparse.ArgumentParser):
|
|||
|
||||
# positionals, optionals and user-defined groups
|
||||
for action_group in self._action_groups:
|
||||
|
||||
# Dirty hack to separate 'subcommands'
|
||||
# into 'actions' and 'subcategories'
|
||||
if action_group.title == "subcommands":
|
||||
|
||||
# Make a copy of the "action group actions"...
|
||||
choice_actions = action_group._group_actions[0]._choices_actions
|
||||
actions_subparser = copy.copy(action_group._group_actions[0])
|
||||
|
@ -504,7 +383,6 @@ class PositionalsFirstHelpFormatter(argparse.HelpFormatter):
|
|||
# wrap the usage parts if it's too long
|
||||
text_width = self._width - self._current_indent
|
||||
if len(prefix) + len(usage) > text_width:
|
||||
|
||||
# break usage into wrappable parts
|
||||
part_regexp = r"\(.*?\)+|\[.*?\]+|\S+"
|
||||
opt_usage = format(optionals, groups)
|
||||
|
@ -568,7 +446,6 @@ class PositionalsFirstHelpFormatter(argparse.HelpFormatter):
|
|||
|
||||
|
||||
class JSONExtendedEncoder(JSONEncoder):
|
||||
|
||||
"""Extended JSON encoder
|
||||
|
||||
Extend default JSON encoder to recognize more types and classes. It will
|
||||
|
@ -581,7 +458,6 @@ class JSONExtendedEncoder(JSONEncoder):
|
|||
"""
|
||||
|
||||
def default(self, o):
|
||||
|
||||
import pytz # Lazy loading, this takes like 3+ sec on a RPi2 ?!
|
||||
|
||||
"""Return a serializable object"""
|
||||
|
|
|
@ -66,14 +66,12 @@ def filter_csrf(callback):
|
|||
|
||||
|
||||
class LogQueues(dict):
|
||||
|
||||
"""Map of session ids to queue."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class APIQueueHandler(logging.Handler):
|
||||
|
||||
"""
|
||||
A handler class which store logging records into a queue, to be used
|
||||
and retrieved from the API.
|
||||
|
@ -86,7 +84,6 @@ class APIQueueHandler(logging.Handler):
|
|||
self.actionsmap = None
|
||||
|
||||
def emit(self, record):
|
||||
|
||||
# Prevent triggering this function while moulinette
|
||||
# is being initialized with --debug
|
||||
if not self.actionsmap or len(request.cookies) == 0:
|
||||
|
@ -110,7 +107,6 @@ class APIQueueHandler(logging.Handler):
|
|||
|
||||
|
||||
class _HTTPArgumentParser:
|
||||
|
||||
"""Argument parser for HTTP requests
|
||||
|
||||
Object for parsing HTTP requests into Python objects. It is based
|
||||
|
@ -235,9 +231,6 @@ class _HTTPArgumentParser:
|
|||
|
||||
return self._parser.parse_args(arg_strings, namespace)
|
||||
|
||||
def dequeue_callbacks(self, *args, **kwargs):
|
||||
return self._parser.dequeue_callbacks(*args, **kwargs)
|
||||
|
||||
def _error(self, message):
|
||||
raise MoulinetteValidationError(message, raw_msg=True)
|
||||
|
||||
|
@ -257,7 +250,6 @@ class _ActionsMapPlugin:
|
|||
api = 2
|
||||
|
||||
def __init__(self, actionsmap, log_queues={}):
|
||||
|
||||
self.actionsmap = actionsmap
|
||||
self.log_queues = log_queues
|
||||
|
||||
|
@ -296,7 +288,7 @@ class _ActionsMapPlugin:
|
|||
)
|
||||
|
||||
# Append routes from the actions map
|
||||
for (m, p) in self.actionsmap.parser.routes:
|
||||
for m, p in self.actionsmap.parser.routes:
|
||||
app.route(p, method=m, callback=self.process)
|
||||
|
||||
def apply(self, callback, context):
|
||||
|
@ -379,7 +371,6 @@ class _ActionsMapPlugin:
|
|||
|
||||
# This is called before each time a route is going to be processed
|
||||
def authenticate(self, authenticator):
|
||||
|
||||
try:
|
||||
session_infos = authenticator.get_session_cookie()
|
||||
except Exception:
|
||||
|
@ -389,13 +380,12 @@ class _ActionsMapPlugin:
|
|||
return session_infos
|
||||
|
||||
def logout(self):
|
||||
|
||||
profile = request.params.get("profile", self.actionsmap.default_authentication)
|
||||
authenticator = self.actionsmap.get_authenticator(profile)
|
||||
|
||||
try:
|
||||
authenticator.get_session_cookie()
|
||||
except KeyError:
|
||||
except Exception:
|
||||
raise HTTPResponse(m18n.g("not_logged_in"), 401)
|
||||
else:
|
||||
# Delete cookie and clean the session
|
||||
|
@ -471,7 +461,6 @@ class _ActionsMapPlugin:
|
|||
else:
|
||||
return format_for_response(ret)
|
||||
finally:
|
||||
|
||||
# Clean upload directory
|
||||
# FIXME do that in a better way
|
||||
global UPLOAD_DIR
|
||||
|
@ -495,7 +484,6 @@ class _ActionsMapPlugin:
|
|||
queue.put(StopIteration)
|
||||
|
||||
def display(self, message, style="info"):
|
||||
|
||||
profile = request.params.get("profile", self.actionsmap.default_authentication)
|
||||
authenticator = self.actionsmap.get_authenticator(profile)
|
||||
s_id = authenticator.get_session_cookie(raise_if_no_session_exists=False)["id"]
|
||||
|
@ -520,7 +508,6 @@ class _ActionsMapPlugin:
|
|||
|
||||
|
||||
def moulinette_error_to_http_response(error):
|
||||
|
||||
content = error.content()
|
||||
if isinstance(content, dict):
|
||||
return HTTPResponse(
|
||||
|
@ -557,7 +544,6 @@ def format_for_response(content):
|
|||
|
||||
|
||||
class ActionsMapParser(BaseActionsMapParser):
|
||||
|
||||
"""Actions map's Parser for the API
|
||||
|
||||
Provide actions map parsing methods for a CLI usage. The parser for
|
||||
|
@ -637,7 +623,6 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
return parser
|
||||
|
||||
def auth_method(self, _, route):
|
||||
|
||||
try:
|
||||
# Retrieve the tid for the route
|
||||
_, parser = self._parsers[route]
|
||||
|
@ -650,6 +635,11 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
|
||||
return parser.authentication
|
||||
|
||||
def want_to_take_lock(self, _, route):
|
||||
_, parser = self._parsers[route]
|
||||
|
||||
return getattr(parser, "want_to_take_lock", True)
|
||||
|
||||
def parse_args(self, args, **kwargs):
|
||||
"""Parse arguments
|
||||
|
||||
|
@ -671,7 +661,6 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
|
||||
# TODO: Catch errors?
|
||||
ret = parser.parse_args(args, ret)
|
||||
parser.dequeue_callbacks(ret)
|
||||
return ret
|
||||
|
||||
# Private methods
|
||||
|
@ -698,7 +687,6 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
|
||||
|
||||
class Interface:
|
||||
|
||||
"""Application Programming Interface for the moulinette
|
||||
|
||||
Initialize a HTTP server which serves the API connected to a given
|
||||
|
@ -715,7 +703,6 @@ class Interface:
|
|||
type = "api"
|
||||
|
||||
def __init__(self, routes={}, actionsmap=None):
|
||||
|
||||
actionsmap = ActionsMap(actionsmap, ActionsMapParser())
|
||||
|
||||
# Attempt to retrieve log queues from an APIQueueHandler
|
||||
|
|
|
@ -208,7 +208,6 @@ def get_locale():
|
|||
|
||||
|
||||
class TTYHandler(logging.StreamHandler):
|
||||
|
||||
"""TTY log handler
|
||||
|
||||
A handler class which prints logging records for a tty. The record is
|
||||
|
@ -274,7 +273,6 @@ class TTYHandler(logging.StreamHandler):
|
|||
|
||||
|
||||
class ActionsMapParser(BaseActionsMapParser):
|
||||
|
||||
"""Actions map's Parser for the CLI
|
||||
|
||||
Provide actions map parsing methods for a CLI usage. The parser for
|
||||
|
@ -289,13 +287,12 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self, parent=None, parser=None, subparser_kwargs=None, top_parser=None, **kwargs
|
||||
self, parent=None, parser=None, subparser_kwargs=None, top_parser=None
|
||||
):
|
||||
super(ActionsMapParser, self).__init__(parent)
|
||||
|
||||
if subparser_kwargs is None:
|
||||
subparser_kwargs = {"title": "categories", "required": False}
|
||||
|
||||
self._parser = parser or ExtendedArgumentParser()
|
||||
self._subparsers = self._parser.add_subparsers(**subparser_kwargs)
|
||||
self.global_parser = parent.global_parser if parent else None
|
||||
|
@ -336,7 +333,11 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
parser = self._subparsers.add_parser(
|
||||
name, description=category_help, help=category_help, **kwargs
|
||||
)
|
||||
return self.__class__(self, parser, {"title": "subcommands", "required": True})
|
||||
return self.__class__(
|
||||
parent=self,
|
||||
parser=parser,
|
||||
subparser_kwargs={"title": "subcommands", "required": True},
|
||||
)
|
||||
|
||||
def add_subcategory_parser(self, name, subcategory_help=None, **kwargs):
|
||||
"""Add a parser for a subcategory
|
||||
|
@ -355,7 +356,11 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
help=subcategory_help,
|
||||
**kwargs,
|
||||
)
|
||||
return self.__class__(self, parser, {"title": "actions", "required": True})
|
||||
return self.__class__(
|
||||
parent=self,
|
||||
parser=parser,
|
||||
subparser_kwargs={"title": "actions", "required": True},
|
||||
)
|
||||
|
||||
def add_action_parser(
|
||||
self,
|
||||
|
@ -388,35 +393,9 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
hide_in_help=hide_in_help,
|
||||
)
|
||||
|
||||
def add_global_arguments(self, arguments):
|
||||
for argument_name, argument_options in arguments.items():
|
||||
# will adapt arguments name for cli or api context
|
||||
names = self.format_arg_names(
|
||||
str(argument_name), argument_options.pop("full", None)
|
||||
)
|
||||
|
||||
self.global_parser.add_argument(*names, **argument_options)
|
||||
|
||||
def auth_method(self, args):
|
||||
# FIXME? idk .. this try/except is duplicated from parse_args below
|
||||
# Just to be able to obtain the tid
|
||||
try:
|
||||
ret = self._parser.parse_args(args)
|
||||
except SystemExit:
|
||||
raise
|
||||
except Exception as e:
|
||||
error_message = "unable to parse arguments '{}' because: {}".format(
|
||||
" ".join(args),
|
||||
e,
|
||||
)
|
||||
logger.exception(error_message)
|
||||
raise MoulinetteValidationError(error_message, raw_msg=True)
|
||||
|
||||
tid = getattr(ret, "_tid", None)
|
||||
|
||||
# Ugh that's for yunohost --version ...
|
||||
if tid is None:
|
||||
return None
|
||||
ret = self.parse_args(args)
|
||||
tid = getattr(ret, "_tid", [])
|
||||
|
||||
# We go down in the subparser tree until we find the leaf
|
||||
# corresponding to the tid with a defined authentication
|
||||
|
@ -429,11 +408,14 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
else:
|
||||
_p = _p._actions[1]
|
||||
|
||||
if tid == []:
|
||||
return None
|
||||
|
||||
raise MoulinetteError(f"Authentication undefined for {tid} ?", raw_msg=True)
|
||||
|
||||
def parse_args(self, args, **kwargs):
|
||||
try:
|
||||
ret = self._parser.parse_args(args)
|
||||
return self._parser.parse_args(args)
|
||||
except SystemExit:
|
||||
raise
|
||||
except Exception as e:
|
||||
|
@ -443,14 +425,25 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
)
|
||||
logger.exception(error_message)
|
||||
raise MoulinetteValidationError(error_message, raw_msg=True)
|
||||
else:
|
||||
self.prepare_action_namespace(getattr(ret, "_tid", None), ret)
|
||||
self._parser.dequeue_callbacks(ret)
|
||||
return ret
|
||||
|
||||
def want_to_take_lock(self, args):
|
||||
ret = self.parse_args(args)
|
||||
tid = getattr(ret, "_tid", [])
|
||||
if len(tid) == 3:
|
||||
_p = self._subparsers.choices[tid[1]]._actions[1].choices[tid[2]]
|
||||
elif len(tid) == 4:
|
||||
_p = (
|
||||
self._subparsers.choices[tid[1]]
|
||||
._actions[1]
|
||||
.choices[tid[2]]
|
||||
._actions[1]
|
||||
.choices[tid[3]]
|
||||
)
|
||||
|
||||
return getattr(_p, "want_to_take_lock", True)
|
||||
|
||||
|
||||
class Interface:
|
||||
|
||||
"""Command-line Interface for the moulinette
|
||||
|
||||
Initialize an interface connected to the standard input/output
|
||||
|
@ -470,7 +463,6 @@ class Interface:
|
|||
actionsmap=None,
|
||||
locales_dir=None,
|
||||
):
|
||||
|
||||
# Set user locale
|
||||
m18n.set_locale(get_locale())
|
||||
|
||||
|
@ -501,6 +493,9 @@ class Interface:
|
|||
if output_as and output_as not in ["json", "plain", "none"]:
|
||||
raise MoulinetteValidationError("invalid_usage")
|
||||
|
||||
if not args:
|
||||
raise MoulinetteValidationError("invalid_usage")
|
||||
|
||||
try:
|
||||
ret = self.actionsmap.process(args, timeout=timeout)
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
|
@ -555,9 +550,7 @@ class Interface:
|
|||
)
|
||||
|
||||
def _prompt(message):
|
||||
|
||||
if not is_multiline:
|
||||
|
||||
import prompt_toolkit
|
||||
from prompt_toolkit.completion import WordCompleter
|
||||
from prompt_toolkit.styles import Style
|
||||
|
|
|
@ -85,7 +85,6 @@ def getHandlersByClass(classinfo, limit=0):
|
|||
|
||||
|
||||
class MoulinetteLogger(Logger):
|
||||
|
||||
"""Custom logger class
|
||||
|
||||
Extend base Logger class to provide the SUCCESS custom log level with
|
||||
|
@ -173,7 +172,6 @@ def getActionLogger(name=None, logger=None, action_id=None):
|
|||
|
||||
|
||||
class ActionFilter:
|
||||
|
||||
"""Extend log record for an optionnal action
|
||||
|
||||
Filter a given record and look for an `action_id` key. If it is not found
|
||||
|
|
|
@ -80,7 +80,6 @@ def call_async_output(args, callback, **kwargs):
|
|||
p = subprocess.Popen(args, **kwargs)
|
||||
|
||||
while p.poll() is None:
|
||||
|
||||
while True:
|
||||
try:
|
||||
callback, message = log_queue.get(True, 1)
|
||||
|
@ -201,7 +200,6 @@ def run_commands(cmds, callback=None, separate_stderr=False, shell=True, **kwarg
|
|||
# Iterate over commands
|
||||
error = 0
|
||||
for cmd in cmds:
|
||||
|
||||
process = subprocess.Popen(
|
||||
cmd, stdout=subprocess.PIPE, stderr=_stderr, shell=shell, **kwargs
|
||||
)
|
||||
|
|
|
@ -4,5 +4,7 @@ ignore =
|
|||
E128,
|
||||
E731,
|
||||
E722,
|
||||
W503 # Black formatter conflict
|
||||
E203 # Black formatter conflict
|
||||
# Black formatter conflict
|
||||
W503,
|
||||
# Black formatter conflict
|
||||
E203
|
2
setup.py
2
setup.py
|
@ -60,7 +60,7 @@ setup(
|
|||
license="AGPL",
|
||||
packages=find_packages(exclude=["test"]),
|
||||
data_files=[("/usr/share/moulinette/locales", locale_files)],
|
||||
python_requires=">=3.7.*, <3.10",
|
||||
python_requires=">=3.7.0,<3.10",
|
||||
install_requires=install_deps,
|
||||
tests_require=test_deps,
|
||||
extras_require=extras,
|
||||
|
|
|
@ -7,21 +7,6 @@ _global:
|
|||
authentication:
|
||||
api: dummy
|
||||
cli: dummy
|
||||
arguments:
|
||||
-v:
|
||||
full: --version
|
||||
help: Display Yoloswag versions
|
||||
action: callback
|
||||
callback:
|
||||
method: test.src.testauth.yoloswag_version
|
||||
return: true
|
||||
-w:
|
||||
full: --wersion
|
||||
help: Not existing function
|
||||
action: callback
|
||||
callback:
|
||||
method: test.src.testauth.not_existing_function
|
||||
return: true
|
||||
|
||||
#############################
|
||||
# Test Actions #
|
||||
|
|
|
@ -12,13 +12,11 @@ reference = json.loads(open(locale_folder + "en.json").read())
|
|||
|
||||
|
||||
def fix_locale(locale_file):
|
||||
|
||||
this_locale = json.loads(open(locale_folder + locale_file).read())
|
||||
fixed_stuff = False
|
||||
|
||||
# We iterate over all keys/string in en.json
|
||||
for key, string in reference.items():
|
||||
|
||||
# Ignore check if there's no translation yet for this key
|
||||
if key not in this_locale:
|
||||
continue
|
||||
|
|
|
@ -76,7 +76,6 @@ def patch_lock(moulinette):
|
|||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def moulinette(tmp_path_factory):
|
||||
|
||||
import moulinette
|
||||
import moulinette.core
|
||||
from moulinette.utils.log import configure_logging
|
||||
|
@ -104,7 +103,6 @@ def moulinette(tmp_path_factory):
|
|||
|
||||
@pytest.fixture
|
||||
def moulinette_webapi(moulinette):
|
||||
|
||||
from webtest import TestApp
|
||||
from webtest.app import CookiePolicy
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ import re
|
|||
|
||||
|
||||
def reformat(lang, transformations):
|
||||
|
||||
locale = open(f"locales/{lang}.json").read()
|
||||
for pattern, replace in transformations.items():
|
||||
locale = re.compile(pattern).sub(replace, locale)
|
||||
|
@ -25,8 +24,8 @@ godamn_spaces_of_hell = [
|
|||
"\u2008",
|
||||
"\u2009",
|
||||
"\u200A",
|
||||
"\u202f",
|
||||
"\u202F",
|
||||
# "\u202f",
|
||||
# "\u202F",
|
||||
"\u3000",
|
||||
]
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ locale_files.remove("en.json")
|
|||
reference = json.loads(open(locale_folder + "en.json").read())
|
||||
|
||||
for locale_file in locale_files:
|
||||
|
||||
print(locale_file)
|
||||
this_locale = json.loads(
|
||||
open(locale_folder + locale_file).read(), object_pairs_hook=OrderedDict
|
||||
|
|
|
@ -13,7 +13,6 @@ session_secret = random_ascii()
|
|||
|
||||
|
||||
class Authenticator(BaseAuthenticator):
|
||||
|
||||
"""Dummy authenticator used for tests"""
|
||||
|
||||
name = "dummy"
|
||||
|
@ -22,14 +21,12 @@ class Authenticator(BaseAuthenticator):
|
|||
pass
|
||||
|
||||
def _authenticate_credentials(self, credentials=None):
|
||||
|
||||
if not credentials == self.name:
|
||||
raise MoulinetteError("invalid_password", raw_msg=True)
|
||||
|
||||
return
|
||||
|
||||
def set_session_cookie(self, infos):
|
||||
|
||||
from bottle import response
|
||||
|
||||
assert isinstance(infos, dict)
|
||||
|
@ -49,7 +46,6 @@ class Authenticator(BaseAuthenticator):
|
|||
)
|
||||
|
||||
def get_session_cookie(self, raise_if_no_session_exists=True):
|
||||
|
||||
from bottle import request
|
||||
|
||||
try:
|
||||
|
@ -68,7 +64,6 @@ class Authenticator(BaseAuthenticator):
|
|||
return infos
|
||||
|
||||
def delete_session_cookie(self):
|
||||
|
||||
from bottle import response
|
||||
|
||||
response.set_cookie("moulitest", "", max_age=-1)
|
||||
|
|
|
@ -13,7 +13,6 @@ session_secret = random_ascii()
|
|||
|
||||
|
||||
class Authenticator(BaseAuthenticator):
|
||||
|
||||
"""Dummy authenticator used for tests"""
|
||||
|
||||
name = "yoloswag"
|
||||
|
@ -22,14 +21,12 @@ class Authenticator(BaseAuthenticator):
|
|||
pass
|
||||
|
||||
def _authenticate_credentials(self, credentials=None):
|
||||
|
||||
if not credentials == self.name:
|
||||
raise MoulinetteError("invalid_password", raw_msg=True)
|
||||
|
||||
return
|
||||
|
||||
def set_session_cookie(self, infos):
|
||||
|
||||
from bottle import response
|
||||
|
||||
assert isinstance(infos, dict)
|
||||
|
@ -49,7 +46,6 @@ class Authenticator(BaseAuthenticator):
|
|||
)
|
||||
|
||||
def get_session_cookie(self, raise_if_no_session_exists=True):
|
||||
|
||||
from bottle import request
|
||||
|
||||
try:
|
||||
|
@ -68,7 +64,6 @@ class Authenticator(BaseAuthenticator):
|
|||
return infos
|
||||
|
||||
def delete_session_cookie(self):
|
||||
|
||||
from bottle import response
|
||||
|
||||
response.set_cookie("moulitest", "", max_age=-1)
|
||||
|
|
|
@ -44,7 +44,3 @@ def testauth_with_extra_str_only(only_a_str):
|
|||
|
||||
def testauth_with_type_int(only_an_int):
|
||||
return only_an_int
|
||||
|
||||
|
||||
def yoloswag_version(*args, **kwargs):
|
||||
return "666"
|
||||
|
|
|
@ -161,7 +161,6 @@ def test_required_paremeter_missing_value(iface, caplog):
|
|||
|
||||
|
||||
def test_actions_map_unknown_authenticator(monkeypatch, tmp_path):
|
||||
|
||||
from moulinette.interfaces.api import ActionsMapParser
|
||||
|
||||
amap = ActionsMap("test/actionsmap/moulitest.yml", ActionsMapParser())
|
||||
|
|
|
@ -255,25 +255,6 @@ class TestAuthCLI:
|
|||
|
||||
assert "invalid_password" in str(exception)
|
||||
|
||||
def test_request_with_callback(self, moulinette_cli, capsys, mocker):
|
||||
mocker.patch("os.isatty", return_value=True)
|
||||
mocker.patch("prompt_toolkit.prompt", return_value="dummy")
|
||||
moulinette_cli.run(["--version"], output_as="plain")
|
||||
message = capsys.readouterr()
|
||||
|
||||
assert "666" in message.out
|
||||
|
||||
moulinette_cli.run(["-v"], output_as="plain")
|
||||
message = capsys.readouterr()
|
||||
|
||||
assert "666" in message.out
|
||||
|
||||
with pytest.raises(MoulinetteError):
|
||||
moulinette_cli.run(["--wersion"], output_as="plain")
|
||||
message = capsys.readouterr()
|
||||
|
||||
assert "cannot get value from callback method" in message.err
|
||||
|
||||
def test_request_with_arg(self, moulinette_cli, capsys, mocker):
|
||||
mocker.patch("os.isatty", return_value=True)
|
||||
mocker.patch("prompt_toolkit.prompt", return_value="dummy")
|
||||
|
|
|
@ -330,7 +330,6 @@ def test_mkdir(tmp_path):
|
|||
|
||||
|
||||
def test_mkdir_with_permission(tmp_path, mocker):
|
||||
|
||||
# This test only make sense when not being root
|
||||
if os.getuid() == 0:
|
||||
return
|
||||
|
|
|
@ -13,12 +13,10 @@ reference = json.loads(open(locale_folder + "en.json").read())
|
|||
|
||||
|
||||
def find_inconsistencies(locale_file):
|
||||
|
||||
this_locale = json.loads(open(locale_folder + locale_file).read())
|
||||
|
||||
# We iterate over all keys/string in en.json
|
||||
for key, string in reference.items():
|
||||
|
||||
# Ignore check if there's no translation yet for this key
|
||||
if key not in this_locale:
|
||||
continue
|
||||
|
|
|
@ -11,7 +11,6 @@ import json
|
|||
|
||||
|
||||
def find_expected_string_keys():
|
||||
|
||||
# Try to find :
|
||||
# m18n.g( "foo"
|
||||
# MoulinetteError("foo"
|
||||
|
@ -69,7 +68,6 @@ def test_undefined_i18n_keys():
|
|||
|
||||
|
||||
def test_unused_i18n_keys():
|
||||
|
||||
unused_keys = keys_defined.difference(expected_string_keys)
|
||||
unused_keys = sorted(unused_keys)
|
||||
|
||||
|
|
|
@ -66,7 +66,6 @@ def test_run_shell_kwargs():
|
|||
|
||||
|
||||
def test_call_async_output(test_file):
|
||||
|
||||
mock_callback_stdout = mock.Mock()
|
||||
mock_callback_stderr = mock.Mock()
|
||||
|
||||
|
@ -118,7 +117,6 @@ def test_call_async_output(test_file):
|
|||
|
||||
|
||||
def test_call_async_output_kwargs(test_file, mocker):
|
||||
|
||||
mock_callback_stdout = mock.Mock()
|
||||
mock_callback_stdinfo = mock.Mock()
|
||||
mock_callback_stderr = mock.Mock()
|
||||
|
|
|
@ -13,12 +13,10 @@ reference = json.loads(open(locale_folder + "en.json").read())
|
|||
|
||||
|
||||
def find_inconsistencies(locale_file):
|
||||
|
||||
this_locale = json.loads(open(locale_folder + locale_file).read())
|
||||
|
||||
# We iterate over all keys/string in en.json
|
||||
for key, string in reference.items():
|
||||
|
||||
# Ignore check if there's no translation yet for this key
|
||||
if key not in this_locale:
|
||||
continue
|
||||
|
|
Loading…
Add table
Reference in a new issue