[fix] Pep8 and syntax

This commit is contained in:
ljf 2022-09-14 18:38:11 +02:00
parent 218865a59e
commit e0fa223d3d
No known key found for this signature in database
6 changed files with 83 additions and 61 deletions

View file

@ -31,7 +31,7 @@ import subprocess
import csv import csv
import tempfile import tempfile
import re import re
import urllib import urllib.parse
from datetime import datetime from datetime import datetime
from packaging import version from packaging import version

View file

@ -22,13 +22,13 @@ import os
import subprocess import subprocess
import json import json
from datetime import datetime from datetime import datetime, timedelta
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette import m18n
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError
from yunohost.repository import LocalBackupRepository from yunohost.utils.network import shf_request
from yunohost.repository import LocalBackupRepository, BackupArchive
logger = getActionLogger("yunohost.repository") logger = getActionLogger("yunohost.repository")
@ -90,14 +90,14 @@ class BorgBackupRepository(LocalBackupRepository):
response = shf_request( response = shf_request(
domain=self.domain, domain=self.domain,
service=services[self.method], service=services[self.method],
shf_id=values.pop('shf_id', None), shf_id=self.values.pop('shf_id', None),
data={ data={
'origin': self.domain, 'origin': self.domain,
'public_key': self.public_key, 'public_key': self.public_key,
'quota': self.quota, 'quota': self.quota,
'alert': self.alert, 'alert': self.alert,
'alert_delay': self.alert_delay, 'alert_delay': self.alert_delay,
#password: "XXXXXXXX", # password: "XXXXXXXX",
} }
) )
self.new_values['shf_id'] = response['id'] self.new_values['shf_id'] = response['id']
@ -123,13 +123,13 @@ class BorgBackupRepository(LocalBackupRepository):
def purge(self): def purge(self):
if self.is_shf: if self.is_shf:
response = shf_request( shf_request(
domain=self.domain, domain=self.domain,
service="borgbackup", service="borgbackup",
shf_id=values.pop('shf_id', None), shf_id=self.values.pop('shf_id', None),
data={ data={
'origin': self.domain, 'origin': self.domain,
#password: "XXXXXXXX", # password: "XXXXXXXX",
} }
) )
else: else:
@ -179,7 +179,7 @@ class BorgBackupRepository(LocalBackupRepository):
continue continue
period = timedelta(**{unit: 1}) period = timedelta(**{unit: 1})
periods += set([(now - period * i, now - period * (i - 1)) periods += set([(now - period * i, now - period * (i - 1))
for i in range(qty)]) for i in range(qty)])
# Delete unneeded archive # Delete unneeded archive
for created_at in sorted(archives, reverse=True): for created_at in sorted(archives, reverse=True):
@ -194,7 +194,7 @@ class BorgBackupRepository(LocalBackupRepository):
class BorgBackupArchive(BackupArchive): class BorgBackupArchive(BackupArchive):
""" Backup prepared files with borg """ """ Backup prepared files with borg """
def backup(self): def backup(self):
cmd = ['borg', 'create', self.archive_path, './'] cmd = ['borg', 'create', self.archive_path, './']
@ -244,5 +244,3 @@ class BorgBackupArchive(BackupArchive):
# FIXME How to be sure the place where we mount is secure ? # FIXME How to be sure the place where we mount is secure ?
cmd = ['borg', 'mount', self.archive_path, path] cmd = ['borg', 'mount', self.archive_path, path]
self.repo._call('mount_archive', cmd) self.repo._call('mount_archive', cmd)

View file

@ -1,3 +1,32 @@
# -*- coding: utf-8 -*-
""" License
Copyright (C) 2013 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
"""
from moulinette import m18n
from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import rm
from yunohost.hook import hook_callback
from yunohost.utils.error import YunohostError
from yunohost.repository import BackupRepository, BackupArchive
logger = getActionLogger("yunohost.repository")
class HookBackupRepository(BackupRepository): class HookBackupRepository(BackupRepository):
method_name = "hook" method_name = "hook"
@ -13,7 +42,7 @@ class HookBackupRepository(BackupRepository):
def remove(self, purge=False): def remove(self, purge=False):
if self.__class__ == BackupRepository: if self.__class__ == BackupRepository:
raise NotImplementedError() # purge raise NotImplementedError() # purge
rm(self.save_path, force=True) rm(self.save_path, force=True)
logger.success(m18n.n("repository_removed", repository=self.shortname)) logger.success(m18n.n("repository_removed", repository=self.shortname))
@ -24,8 +53,8 @@ class HookBackupRepository(BackupRepository):
def info(self, space_used=False): def info(self, space_used=False):
result = super().get(mode="export") result = super().get(mode="export")
if self.__class__ == BackupRepository and space_used == True: if self.__class__ == BackupRepository and space_used is True:
raise NotImplementedError() # purge raise NotImplementedError() # purge
return {self.shortname: result} return {self.shortname: result}
@ -44,7 +73,7 @@ class HookBackupArchive(BackupArchive):
""" """
self._call('backup', self.work_dir, self.name, self.repo.location, self.manager.size, self._call('backup', self.work_dir, self.name, self.repo.location, self.manager.size,
self.manager.description) self.manager.description)
def restore(self): def restore(self):
raise NotImplementedError() raise NotImplementedError()
@ -64,7 +93,7 @@ class HookBackupArchive(BackupArchive):
return result return result
def info(self): def info(self):
raise NotImplementedError() #compute_space_used raise NotImplementedError() # compute_space_used
""" Return json string of the info.json file """ Return json string of the info.json file
Exceptions: Exceptions:
@ -82,7 +111,7 @@ class HookBackupArchive(BackupArchive):
""" """
super().mount() super().mount()
self._call('mount', self.work_dir, self.name, self.repo.location, self.manager.size, self._call('mount', self.work_dir, self.name, self.repo.location, self.manager.size,
self.manager.description) self.manager.description)
def extract(self): def extract(self):
raise NotImplementedError() raise NotImplementedError()
@ -97,6 +126,7 @@ class HookBackupArchive(BackupArchive):
except YunohostError: except YunohostError:
return False return False
return True return True
def _call(self, *args): def _call(self, *args):
""" Call a submethod of backup method hook """ Call a submethod of backup method hook

View file

@ -235,4 +235,3 @@ class TarBackupArchive:
if not os.path.exists(archive_file): if not os.path.exists(archive_file):
raise YunohostError('backup_archive_broken_link', raise YunohostError('backup_archive_broken_link',
path=archive_file) path=archive_file)

View file

@ -23,25 +23,26 @@
Manage backup repositories Manage backup repositories
""" """
import json
import os import os
import re import re
import time import shutil
import subprocess import subprocess
import re import tarfile
import urllib.parse import tempfile
from moulinette import Moulinette, m18n from moulinette import Moulinette, m18n
from moulinette.core import MoulinetteError from moulinette.core import MoulinetteError
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_file, read_yaml, write_to_json, rm, mkdir, chmod, chown from moulinette.utils.filesystem import read_file, rm, mkdir
from moulinette.utils.network import download_text, download_json from moulinette.utils.network import download_text
from datetime import timedelta, datetime
from yunohost.utils.config import ConfigPanel, Question from yunohost.utils.config import ConfigPanel
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.utils.filesystem import space_used_in_directory, disk_usage, binary_to_human from yunohost.utils.filesystem import disk_usage, binary_to_human, free_space_in_directory
from yunohost.utils.network import get_ssh_public_key, shf_request, SHF_BASE_URL from yunohost.utils.network import get_ssh_public_key, SHF_BASE_URL
from yunohost.log import OperationLogger, is_unit_operation
logger = getActionLogger('yunohost.repository') logger = getActionLogger('yunohost.repository')
REPOSITORIES_DIR = '/etc/yunohost/repositories' REPOSITORIES_DIR = '/etc/yunohost/repositories'
@ -104,12 +105,11 @@ class BackupRepository(ConfigPanel):
for repo in repositories: for repo in repositories:
try: try:
repositories[repo] = BackupRepository(repo).info(space_used) repositories[repo] = BackupRepository(repo).info(space_used)
except Exception as e: except Exception:
logger.error(f"Unable to open repository {repo}") logger.error(f"Unable to open repository {repo}")
return repositories return repositories
# ================================================= # =================================================
# Config Panel Hooks # Config Panel Hooks
# ================================================= # =================================================
@ -117,19 +117,18 @@ class BackupRepository(ConfigPanel):
def post_ask__domain(self, question): def post_ask__domain(self, question):
""" Detect if the domain support Self-Hosting Federation protocol """ Detect if the domain support Self-Hosting Federation protocol
""" """
#import requests # import requests
# FIXME What if remote server is self-signed ? # FIXME What if remote server is self-signed ?
# FIXME What if remote server is unreachable temporarily ? # FIXME What if remote server is unreachable temporarily ?
url = SHF_BASE_URL.format(domain=question.value) + "/" url = SHF_BASE_URL.format(domain=question.value) + "/"
try: try:
#r = requests.get(url, timeout=10) # r = requests.get(url, timeout=10)
download_text(url, timeout=10) download_text(url, timeout=10)
except MoulinetteError as e: except MoulinetteError:
logger.debug("SHF not running") logger.debug("SHF not running")
return { 'is_shf': False } return {'is_shf': False}
logger.debug("SHF running") logger.debug("SHF running")
return { 'is_shf': True } return {'is_shf': True}
# ================================================= # =================================================
# Config Panel Override # Config Panel Override
@ -156,7 +155,7 @@ class BackupRepository(ConfigPanel):
def _parse_pre_answered(self, *args): def _parse_pre_answered(self, *args):
super()._parse_pre_answered(*args) super()._parse_pre_answered(*args)
if 'location' in self.args: if 'location' in self.args:
self.args.update(BackupRepository.split_location(self.args['location'])) self.args.update(BackupRepository.split_location(self.args['location']))
if 'domain' in self.args: if 'domain' in self.args:
self.args['is_remote'] = bool(self.args['domain']) self.args['is_remote'] = bool(self.args['domain'])
@ -179,7 +178,6 @@ class BackupRepository(ConfigPanel):
self.new_values.pop(prop, None) self.new_values.pop(prop, None)
super()._apply() super()._apply()
# ================================================= # =================================================
# BackupMethod encapsulation # BackupMethod encapsulation
# ================================================= # =================================================
@ -237,7 +235,7 @@ class BackupRepository(ConfigPanel):
def info(self, space_used=False): def info(self, space_used=False):
result = super().get(mode="export") result = super().get(mode="export")
if self.__class__ == BackupRepository and space_used == True: if self.__class__ == BackupRepository and space_used is True:
result["space_used"] = self.compute_space_used() result["space_used"] = self.compute_space_used()
return {self.shortname: result} return {self.shortname: result}
@ -245,7 +243,7 @@ class BackupRepository(ConfigPanel):
def list(self, with_info): def list(self, with_info):
archives = self.list_archive_name() archives = self.list_archive_name()
if with_info: if with_info:
d = OrderedDict() d = {}
for archive in archives: for archive in archives:
try: try:
d[archive] = BackupArchive(repo=self, name=archive).info() d[archive] = BackupArchive(repo=self, name=archive).info()
@ -289,7 +287,7 @@ class BackupRepository(ConfigPanel):
continue continue
period = timedelta(**{unit: 1}) period = timedelta(**{unit: 1})
periods += set([(now - period * i, now - period * (i - 1)) periods += set([(now - period * i, now - period * (i - 1))
for i in range(qty)]) for i in range(qty)])
# Delete unneeded archive # Delete unneeded archive
for created_at in sorted(archives, reverse=True): for created_at in sorted(archives, reverse=True):
@ -412,7 +410,7 @@ class BackupArchive:
raise YunohostError( raise YunohostError(
"backup_archive_cant_retrieve_info_json", archive=self.archive_path "backup_archive_cant_retrieve_info_json", archive=self.archive_path
) )
extract_paths = []
if f"{leading_dot}backup.csv" in files_in_archive: if f"{leading_dot}backup.csv" in files_in_archive:
yield f"{leading_dot}backup.csv" yield f"{leading_dot}backup.csv"
else: else:
@ -447,7 +445,7 @@ class BackupArchive:
if not os.path.lexists(archive_file): if not os.path.lexists(archive_file):
archive_file += ".gz" archive_file += ".gz"
if not os.path.lexists(archive_file): if not os.path.lexists(archive_file):
raise YunohostValidationError("backup_archive_name_unknown", name=name) raise YunohostValidationError("backup_archive_name_unknown", name=self.name)
# If symlink, retrieve the real path # If symlink, retrieve the real path
if os.path.islink(archive_file): if os.path.islink(archive_file):
@ -491,7 +489,7 @@ class BackupArchive:
raise YunohostError('backup_info_json_not_implemented') raise YunohostError('backup_info_json_not_implemented')
try: try:
info = json.load(info_json) info = json.load(info_json)
except: except Exception:
logger.debug("unable to load info json", exc_info=1) logger.debug("unable to load info json", exc_info=1)
raise YunohostError('backup_invalid_archive') raise YunohostError('backup_invalid_archive')
@ -558,7 +556,8 @@ class BackupArchive:
raise YunohostError("backup_cleaning_failed") raise YunohostError("backup_cleaning_failed")
if self.manager.is_tmp_work_dir: if self.manager.is_tmp_work_dir:
filesystem.rm(self.work_dir, True, True) rm(self.work_dir, True, True)
def _organize_files(self): def _organize_files(self):
""" """
Mount all csv src in their related path Mount all csv src in their related path
@ -587,11 +586,11 @@ class BackupArchive:
# Be sure the parent dir of destination exists # Be sure the parent dir of destination exists
if not os.path.isdir(dest_dir): if not os.path.isdir(dest_dir):
filesystem.mkdir(dest_dir, parents=True) mkdir(dest_dir, parents=True)
# For directory, attempt to mount bind # For directory, attempt to mount bind
if os.path.isdir(src): if os.path.isdir(src):
filesystem.mkdir(dest, parents=True, force=True) mkdir(dest, parents=True, force=True)
try: try:
subprocess.check_call(["mount", "--rbind", src, dest]) subprocess.check_call(["mount", "--rbind", src, dest])
@ -688,7 +687,6 @@ class BackupArchive:
if self.__class__ == BackupArchive: if self.__class__ == BackupArchive:
raise NotImplementedError() raise NotImplementedError()
def download(self): def download(self):
if self.__class__ == BackupArchive: if self.__class__ == BackupArchive:
raise NotImplementedError() raise NotImplementedError()
@ -712,9 +710,3 @@ class BackupArchive:
def mount(self): def mount(self):
if self.__class__ == BackupArchive: if self.__class__ == BackupArchive:
raise NotImplementedError() raise NotImplementedError()

View file

@ -49,10 +49,13 @@ from yunohost.log import OperationLogger
logger = getActionLogger("yunohost.config") logger = getActionLogger("yunohost.config")
CONFIG_PANEL_VERSION_SUPPORTED = 1.0 CONFIG_PANEL_VERSION_SUPPORTED = 1.0
# Those js-like evaluate functions are used to eval safely visible attributes
# The goal is to evaluate in the same way than js simple-evaluate
# https://github.com/shepherdwind/simple-evaluate
def evaluate_simple_ast(node, context=None): def evaluate_simple_ast(node, context=None):
"""
Those js-like evaluate functions are used to eval safely visible attributes
The goal is to evaluate in the same way than js simple-evaluate
https://github.com/shepherdwind/simple-evaluate
"""
if context is None: if context is None:
context = {} context = {}
@ -1130,9 +1133,9 @@ class DomainQuestion(Question):
@staticmethod @staticmethod
def normalize(value, option={}): def normalize(value, option={}):
if value.startswith("https://"): if value.startswith("https://"):
value = value[len("https://") :] value = value[len("https://"):]
elif value.startswith("http://"): elif value.startswith("http://"):
value = value[len("http://") :] value = value[len("http://"):]
# Remove trailing slashes # Remove trailing slashes
value = value.rstrip("/").lower() value = value.rstrip("/").lower()