mirror of
https://github.com/borgbase/vorta
synced 2025-01-03 05:36:19 +00:00
Distinguish different errors in case borg check
failed. By @real-yfprojects (#1163)
This commit is contained in:
parent
4b5b7e20ef
commit
23c47673c0
3 changed files with 88 additions and 19 deletions
|
@ -1,25 +1,26 @@
|
|||
import logging
|
||||
import os
|
||||
import sys
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
|
||||
from vorta.borg.create import BorgCreateJob
|
||||
from vorta.borg.version import BorgVersionJob
|
||||
from vorta.borg.break_lock import BorgBreakJob
|
||||
from vorta.config import TEMP_DIR, PROFILE_BOOTSTRAP_FILE
|
||||
from vorta.borg.create import BorgCreateJob
|
||||
from vorta.borg.jobs_manager import JobsManager
|
||||
from vorta.borg.version import BorgVersionJob
|
||||
from vorta.config import PROFILE_BOOTSTRAP_FILE, TEMP_DIR
|
||||
from vorta.i18n import init_translations, translate
|
||||
from vorta.store.models import BackupProfileModel, SettingsModel
|
||||
from vorta.store.connection import cleanup_db
|
||||
from vorta.notifications import VortaNotifications
|
||||
from vorta.profile_export import ProfileExport
|
||||
from vorta.qt_single_application import QtSingleApplication
|
||||
from vorta.scheduler import VortaScheduler
|
||||
from vorta.borg.jobs_manager import JobsManager
|
||||
from vorta.store.connection import cleanup_db
|
||||
from vorta.store.models import BackupProfileModel, SettingsModel
|
||||
from vorta.tray_menu import TrayMenu
|
||||
from vorta.utils import borg_compat, parse_args
|
||||
from vorta.views.main_window import MainWindow
|
||||
from vorta.notifications import VortaNotifications
|
||||
from vorta.profile_export import ProfileExport
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -39,7 +40,7 @@ class VortaApp(QtSingleApplication):
|
|||
backup_cancelled_event = QtCore.pyqtSignal()
|
||||
backup_log_event = QtCore.pyqtSignal(str, dict)
|
||||
backup_progress_event = QtCore.pyqtSignal(str)
|
||||
check_failed_event = QtCore.pyqtSignal(str)
|
||||
check_failed_event = QtCore.pyqtSignal(dict)
|
||||
|
||||
def __init__(self, args_raw, single_app=False):
|
||||
super().__init__(APP_ID, args_raw)
|
||||
|
@ -288,11 +289,62 @@ def bootstrap_profile(self, bootstrap_file=PROFILE_BOOTSTRAP_FILE):
|
|||
default_profile = BackupProfileModel(name='Default')
|
||||
default_profile.save()
|
||||
|
||||
def check_failed_response(self, repo_url):
|
||||
msg = QMessageBox()
|
||||
msg.setIcon(QMessageBox.Critical)
|
||||
msg.setStandardButtons(QMessageBox.Ok)
|
||||
msg.setWindowTitle(self.tr('Repo Check Failed'))
|
||||
msg.setText(self.tr('Repository data check for repo %s failed') % repo_url)
|
||||
msg.setInformativeText(self.tr('Repair or recreate the repository soon to avoid missing data.'))
|
||||
msg.exec()
|
||||
def check_failed_response(self, result: Dict[str, Any]):
|
||||
"""
|
||||
Process the signal that a repo consistency check failed.
|
||||
|
||||
Displays a `QMessageBox` with an error message depending on the
|
||||
return code of the `BorgJob`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
repo_url : str
|
||||
The url of the repo of concern
|
||||
"""
|
||||
# extract data from the params for the borg job
|
||||
repo_url = result['params']['repo_url']
|
||||
returncode = result['returncode']
|
||||
errors: List[Tuple[int, str]] = result['errors']
|
||||
error_message = errors[0][1] if errors else ''
|
||||
|
||||
# Switch over returncodes
|
||||
if returncode == 0:
|
||||
# No fail
|
||||
logger.warning(
|
||||
'VortaApp.check_failed_response was called with returncode 0')
|
||||
elif returncode == 130:
|
||||
# Keyboard interupt
|
||||
pass
|
||||
else: # Real error
|
||||
# Create QMessageBox
|
||||
msg = QMessageBox()
|
||||
msg.setIcon(QMessageBox.Icon.Critical) # changed for warning
|
||||
msg.setStandardButtons(QMessageBox.Ok)
|
||||
msg.setWindowTitle(self.tr('Repo Check Failed'))
|
||||
|
||||
if returncode == 1:
|
||||
# warning
|
||||
msg.setIcon(QMessageBox.Icon.Warning)
|
||||
text = self.tr('Borg exited with a warning message. See logs for details.')
|
||||
infotext = error_message
|
||||
elif returncode > 128:
|
||||
# 128+N - killed by signal N (e.g. 137 == kill -9)
|
||||
signal = returncode - 128
|
||||
text = (
|
||||
self.tr('Repository data check for repo was killed by signal %s.')
|
||||
% (signal)
|
||||
)
|
||||
infotext = self.tr('The process running the check job got a kill signal. Try again.')
|
||||
else:
|
||||
# Real error
|
||||
text = (
|
||||
self.tr('Repository data check for repo %s failed. Error code %s')
|
||||
% (repo_url, returncode)
|
||||
)
|
||||
infotext = error_message + '\n'
|
||||
infotext += self.tr('Consider repairing or recreating the repository soon to avoid missing data.')
|
||||
|
||||
msg.setText(text)
|
||||
msg.setInformativeText(infotext)
|
||||
# Display messagebox
|
||||
msg.exec()
|
||||
|
|
|
@ -214,6 +214,7 @@ def run(self):
|
|||
|
||||
p = Popen(self.cmd, stdout=PIPE, stderr=PIPE, bufsize=1, universal_newlines=True,
|
||||
env=self.env, cwd=self.cwd, start_new_session=True)
|
||||
error_messages = [] # List of error messages included in the result
|
||||
|
||||
self.process = p
|
||||
|
||||
|
@ -250,6 +251,11 @@ def read_async(fd):
|
|||
f'{parsed["levelname"]}: {parsed["message"]}', context)
|
||||
level_int = getattr(logging, parsed["levelname"])
|
||||
logger.log(level_int, parsed["message"])
|
||||
|
||||
if level_int >= logging.WARNING:
|
||||
# Append log to list of error messages
|
||||
error_messages.append((level_int, parsed["message"]))
|
||||
|
||||
elif parsed['type'] == 'file_status':
|
||||
self.app.backup_log_event.emit(f'{parsed["path"]} ({parsed["status"]})', {})
|
||||
elif parsed['type'] == 'archive_progress':
|
||||
|
@ -275,6 +281,7 @@ def read_async(fd):
|
|||
'params': self.params,
|
||||
'returncode': self.process.returncode,
|
||||
'cmd': self.cmd,
|
||||
'errors': error_messages,
|
||||
}
|
||||
stdout = ''.join(stdout)
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from typing import Any, Dict
|
||||
|
||||
from .borg_job import BorgJob
|
||||
|
||||
|
||||
|
@ -7,12 +9,20 @@ def started_event(self):
|
|||
self.app.backup_started_event.emit()
|
||||
self.app.backup_progress_event.emit(self.tr('Starting consistency check...'))
|
||||
|
||||
def finished_event(self, result):
|
||||
def finished_event(self, result: Dict[str, Any]):
|
||||
"""
|
||||
Process that the job terminated with the given results.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
result : Dict[str, Any]
|
||||
The (json-like) dictionary containing the job results.
|
||||
"""
|
||||
self.app.backup_finished_event.emit(result)
|
||||
self.result.emit(result)
|
||||
if result['returncode'] != 0:
|
||||
self.app.backup_progress_event.emit(self.tr('Repo check failed. See logs for details.'))
|
||||
self.app.check_failed_event.emit(self.params['repo_url'])
|
||||
self.app.check_failed_event.emit(result)
|
||||
else:
|
||||
self.app.backup_progress_event.emit(self.tr('Check completed.'))
|
||||
|
||||
|
|
Loading…
Reference in a new issue