[fix] Backup legacy tar

This commit is contained in:
ljf 2022-10-25 01:22:53 +02:00
parent 3a6f1bd612
commit 5760e8fe53
No known key found for this signature in database
4 changed files with 40 additions and 21 deletions

View file

@ -1050,6 +1050,7 @@ backup:
-p:
full: --prefix
help: Prefix of the backup archive
default: ""
extra:
pattern: &pattern_backup_archive_prefix
- !!str ^[\w\-\._]{1,35}$
@ -1307,7 +1308,7 @@ backup:
help: Keep all archives within this time interval
extra:
pattern: &pattern_interval
- !!str ^\d+[Hdwmy]$
- !!str ^\d+[Hdw]$
- "pattern_interval"

View file

@ -156,11 +156,11 @@ class BorgBackupRepository(LocalBackupRepository):
# password: "XXXXXXXX",
}
)
else:
elif self.is_remote:
cmd = ["borg", "delete", self.location]
self._call('purge', cmd)
if not self.is_remote:
super().purge()
else:
super().purge()
def list_archives_names(self, prefix=None):
cmd = ["borg", "list", "--json", self.location]

View file

@ -18,19 +18,21 @@
along with this program; if not, see http://www.gnu.org/licenses
"""
import glob
import os
import tarfile
import shutil
from glob import glob
from datetime import datetime
from moulinette.utils.log import getActionLogger
from moulinette import m18n
from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.utils.filesystem import free_space_in_directory
from yunohost.repository import LocalBackupRepository
from yunohost.repository import LocalBackupRepository, BackupArchive
from yunohost.backup import BackupManager
from yunohost.utils.filesystem import space_used_in_directory
from yunohost.utils.system import space_used_by_directory, free_space_in_directory
from yunohost.settings import settings_get
logger = getActionLogger("yunohost.repository")
@ -66,16 +68,13 @@ class TarBackupRepository(LocalBackupRepository):
return [remove_extension(f) for f in archives]
def compute_space_used(self):
return space_used_in_directory(self.location)
return space_used_by_directory(self.location)
def compute_free_space(self):
return free_space_in_directory(self.location)
def prune(self):
raise NotImplementedError()
class TarBackupArchive:
class TarBackupArchive(BackupArchive):
@property
def archive_path(self):
@ -166,7 +165,7 @@ class TarBackupArchive:
logger.debug("unable to delete '%s'", backup_file, exc_info=1)
logger.warning(m18n.n("backup_delete_error", path=backup_file))
def list(self):
def list(self, with_info=False):
try:
tar = tarfile.open(
self.archive_path,
@ -179,14 +178,28 @@ class TarBackupArchive:
raise YunohostError("backup_archive_open_failed")
try:
return tar.getnames()
if not with_info:
return "\n".join(tar.getnames())
else:
return {f.name: {
"mode": f.mode, # FIXME Numeric or letter mode
"type": int(f.type),
"uid": f.uid,
"gid": f.gid,
"user": f.uname,
"group": f.gname,
"size": f.size,
"mtime": datetime.fromtimestamp(f.mtime).isoformat(),
"linktarget": f.linkname,
}
for f in tar.getmembers()}
except (IOError, EOFError, tarfile.ReadError) as e:
tar.close()
raise YunohostError(
"backup_archive_corrupted", archive=self.archive_path, error=str(e)
)
def download(self):
def download(self, exclude_paths=[]):
super().download()
# If symlink, retrieve the real path
archive_file = self.archive_path
@ -206,9 +219,9 @@ class TarBackupArchive:
archive_folder, archive_file_name = archive_file.rsplit("/", 1)
return static_file(archive_file_name, archive_folder, download=archive_file_name)
def extract(self, paths=None, exclude_paths=[]):
paths, exclude_paths = super().extract(paths, exclude_paths)
# Mount the tarball
def extract(self, paths=[], destination=None, exclude_paths=[]):
paths, destination, exclude_paths = super().extract(paths, destination, exclude_paths)
# Open the tarball
try:
tar = tarfile.open(
self.archive_path,
@ -228,10 +241,10 @@ class TarBackupArchive:
and all([not tarinfo.name.startswith(path) for path in exclude_paths])
)
]
tar.extractall(members=subdir_and_files, path=self.work_dir)
tar.extractall(members=subdir_and_files, path=destination)
tar.close()
def mount(self):
def mount(self, path):
raise NotImplementedError()
def _archive_exists(self):

View file

@ -162,6 +162,8 @@ class BackupRepository(ConfigPanel):
return {}
def post_ask__method(self, question):
if question.value:
self.method = question.value
self._cast_by_backup_method()
return {}
@ -351,6 +353,8 @@ class BackupRepository(ConfigPanel):
keep_last -= 1
continue
# TODO Improve performances by creating a BackupRepository.delete_archives()
# method to delete several archives in one command
archives[created_at].delete()
# =================================================
@ -384,6 +388,7 @@ class LocalBackupRepository(BackupRepository):
self.install()
def purge(self):
# FIXME Manage the case where a repository is inside this repository...
rm(self.location, recursive=True, force=True)