Compare commits

...

4 Commits

Author SHA1 Message Date
Aryaman Sharma ed88504d47
Merge 42549de806 into 9cabbbd193 2024-04-28 04:02:47 +05:30
Manu 9cabbbd193 Input to change macOS version for building 2024-04-08 16:24:31 +01:00
Aryaman 42549de806 storing last status for BackupProfiles 2024-03-13 22:40:16 +05:30
Aryaman e843fff945 show progress and logs only for currently selected profile 2024-03-08 16:39:03 +05:30
17 changed files with 105 additions and 40 deletions

View File

@ -3,17 +3,21 @@ on:
workflow_dispatch:
inputs:
branch:
description: 'Branch to use for building macOS release'
description: 'Branch to use for building release'
required: true
default: 'master'
borg_version:
description: 'Borg version to package'
required: true
default: '1.2.1'
default: '1.2.8'
macos_version:
description: 'macOS version for building'
required: true
default: 'macos-11'
jobs:
build:
runs-on: macos-11
runs-on: ${{ github.event.inputs.macos_version }}
steps:
- name: Check out selected branch

View File

@ -40,7 +40,7 @@ class VortaApp(QtSingleApplication):
backup_finished_event = QtCore.pyqtSignal(dict)
backup_cancelled_event = QtCore.pyqtSignal()
backup_log_event = QtCore.pyqtSignal(str, dict)
backup_progress_event = QtCore.pyqtSignal(str)
backup_progress_event = QtCore.pyqtSignal(int, str)
check_failed_event = QtCore.pyqtSignal(dict)
def __init__(self, args_raw, single_app=False):
@ -121,7 +121,7 @@ class VortaApp(QtSingleApplication):
translate('messages', msg['message']),
level='error',
)
self.backup_progress_event.emit(f"[{profile.name}] {translate('messages', msg['message'])}")
self.backup_progress_event.emit(profile.id, f"[{profile.name}] {translate('messages', msg['message'])}")
return None
def open_main_window_action(self):
@ -257,7 +257,7 @@ class VortaApp(QtSingleApplication):
def break_lock(self, profile):
params = BorgBreakJob.prepare(profile)
if not params['ok']:
self.backup_progress_event.emit(f"[{profile.name}] {params['message']}")
self.backup_progress_event.emit(profile.id, f"[{profile.name}] {params['message']}")
return
job = BorgBreakJob(params['cmd'], params)
self.jobs_manager.add_job(job)

View File

@ -296,7 +296,9 @@ class BorgJob(JobInterface, BackupProfileMixin):
# f"{translate('BorgJob','Compressed')}: {pretty_bytes(parsed['compressed_size'])}, "
f"{translate('BorgJob','Deduplicated')}: {pretty_bytes(parsed['deduplicated_size'])}" # noqa: E501
)
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {msg}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {msg}"
)
except json.decoder.JSONDecodeError:
msg = line.strip()
if msg: # Log only if there is something to log.

View File

@ -4,12 +4,15 @@ from .borg_job import BorgJob
class BorgBreakJob(BorgJob):
def started_event(self):
self.app.backup_started_event.emit()
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Breaking repository lock…')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Breaking repository lock…')}"
)
def finished_event(self, result):
self.app.backup_finished_event.emit(result)
self.app.backup_progress_event.emit(
f"[{self.params['profile_name']}] {self.tr('Repository lock broken. Please redo your last action.')}"
self.params['profile_id'],
f"[{self.params['profile_name']}] {self.tr('Repository lock broken. Please redo your last action.')}",
)
self.result.emit(result)

View File

@ -10,7 +10,9 @@ from .borg_job import BorgJob
class BorgCheckJob(BorgJob):
def started_event(self):
self.app.backup_started_event.emit()
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Starting consistency check…')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Starting consistency check…')}"
)
def finished_event(self, result: Dict[str, Any]):
"""
@ -25,14 +27,17 @@ class BorgCheckJob(BorgJob):
self.result.emit(result)
if result['returncode'] != 0:
self.app.backup_progress_event.emit(
self.params['profile_id'],
f"[{self.params['profile_name']}] "
+ translate('RepoCheckJob', 'Repo check failed. See the <a href="{0}">logs</a> for details.').format(
config.LOG_DIR.as_uri()
)
),
)
self.app.check_failed_event.emit(result)
else:
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Check completed.')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Check completed.')}"
)
@classmethod
def prepare(cls, profile):

View File

@ -11,7 +11,7 @@ class BorgCompactJob(BorgJob):
def started_event(self):
self.app.backup_started_event.emit()
self.app.backup_progress_event.emit(
f"[{self.params['profile_name']} {self.tr('Starting repository compaction...')}]"
self.params['profile_id'], f"[{self.params['profile_name']} {self.tr('Starting repository compaction...')}]"
)
def finished_event(self, result: Dict[str, Any]):
@ -27,13 +27,16 @@ class BorgCompactJob(BorgJob):
self.result.emit(result)
if result['returncode'] != 0:
self.app.backup_progress_event.emit(
self.params['profile_id'],
f"[{self.params['profile_name']}] "
+ translate(
'BorgCompactJob', 'Errors during compaction. See the <a href="{0}">logs</a> for details.'
).format(config.LOG_DIR.as_uri())
).format(config.LOG_DIR.as_uri()),
)
else:
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Compaction completed.')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Compaction completed.')}"
)
@classmethod
def prepare(cls, profile):

View File

@ -43,22 +43,26 @@ class BorgCreateJob(BorgJob):
if result['returncode'] == 1:
self.app.backup_progress_event.emit(
self.params['profile_id'],
f"[{self.params['profile_name']}] "
+ translate(
'BorgCreateJob',
'Backup finished with warnings. See the <a href="{0}">logs</a> for details.',
).format(config.LOG_DIR.as_uri())
).format(config.LOG_DIR.as_uri()),
)
else:
self.app.backup_log_event.emit('', {})
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Backup finished.')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Backup finished.')}"
)
def progress_event(self, fmt):
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {fmt}")
self.app.backup_progress_event.emit(self.params['profile_id'], f"[{self.params['profile_name']}] {fmt}")
def started_event(self):
self.app.backup_started_event.emit()
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Backup started.')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Backup started.')}"
)
def finished_event(self, result):
self.app.backup_finished_event.emit(result)

View File

@ -9,7 +9,9 @@ from .borg_job import BorgJob
class BorgDeleteJob(BorgJob):
def started_event(self):
self.app.backup_started_event.emit()
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Deleting archive…')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Deleting archive…')}"
)
def finished_event(self, result):
# set repo stats to N/A
@ -22,7 +24,9 @@ class BorgDeleteJob(BorgJob):
self.app.backup_finished_event.emit(result)
self.result.emit(result)
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Archive deleted.')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Archive deleted.')}"
)
@classmethod
def prepare(cls, profile, archives: List[str]):

View File

@ -7,13 +7,15 @@ class BorgDiffJob(BorgJob):
def started_event(self):
self.app.backup_started_event.emit()
self.app.backup_progress_event.emit(
f"[{self.params['profile_name']}] {self.tr('Requesting differences between archives…')}"
self.params['profile_id'],
f"[{self.params['profile_name']}] {self.tr('Requesting differences between archives…')}",
)
def finished_event(self, result):
self.app.backup_finished_event.emit(result)
self.app.backup_progress_event.emit(
f"[{self.params['profile_name']}] {self.tr('Obtained differences between archives.')}"
self.params['profile_id'],
f"[{self.params['profile_name']}] {self.tr('Obtained differences between archives.')}",
)
self.result.emit(result)

View File

@ -13,14 +13,14 @@ class BorgExtractJob(BorgJob):
def started_event(self):
self.app.backup_started_event.emit()
self.app.backup_progress_event.emit(
f"[{self.params['profile_name']}] {self.tr('Downloading files from archive…')}"
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Downloading files from archive…')}"
)
def finished_event(self, result):
self.app.backup_finished_event.emit(result)
self.result.emit(result)
self.app.backup_progress_event.emit(
f"[{self.params['profile_name']}] {self.tr('Restored files from archive.')}"
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Restored files from archive.')}"
)
@classmethod

View File

@ -7,12 +7,16 @@ from .borg_job import BorgJob
class BorgInfoArchiveJob(BorgJob):
def started_event(self):
self.app.backup_started_event.emit()
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Refreshing archive…')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Refreshing archive…')}"
)
def finished_event(self, result):
self.app.backup_finished_event.emit(result)
self.result.emit(result)
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Refreshing archive done.')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Refreshing archive done.')}"
)
@classmethod
def prepare(cls, profile, archive_name):

View File

@ -6,12 +6,14 @@ from .borg_job import BorgJob
class BorgListArchiveJob(BorgJob):
def started_event(self):
self.app.backup_started_event.emit()
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Getting archive content…')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Getting archive content…')}"
)
def finished_event(self, result):
self.app.backup_finished_event.emit(result)
self.app.backup_progress_event.emit(
f"[{self.params['profile_name']}] {self.tr('Done getting archive content.')}"
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Done getting archive content.')}"
)
self.result.emit(result)

View File

@ -9,12 +9,16 @@ from .borg_job import BorgJob
class BorgListRepoJob(BorgJob):
def started_event(self):
self.app.backup_started_event.emit()
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Refreshing archives…')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Refreshing archives…')}"
)
def finished_event(self, result):
self.app.backup_finished_event.emit(result)
self.result.emit(result)
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Refreshing archives done.')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Refreshing archives done.')}"
)
@classmethod
def prepare(cls, profile):

View File

@ -7,7 +7,9 @@ from .borg_job import BorgJob
class BorgPruneJob(BorgJob):
def started_event(self):
self.app.backup_started_event.emit()
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Pruning old archives…')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Pruning old archives…')}"
)
def finished_event(self, result):
# set repo stats to N/A
@ -20,7 +22,9 @@ class BorgPruneJob(BorgJob):
self.app.backup_finished_event.emit(result)
self.result.emit(result)
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Pruning done.')}")
self.app.backup_progress_event.emit(
self.params['profile_id'], f"[{self.params['profile_name']}] {self.tr('Pruning done.')}"
)
@classmethod
def prepare(cls, profile):

View File

@ -102,6 +102,7 @@ class BackupProfileModel(BaseModel):
pre_backup_cmd = pw.CharField(default='')
post_backup_cmd = pw.CharField(default='')
dont_run_on_metered_networks = pw.BooleanField(default=True)
last_status = pw.CharField(default='', null=True)
def refresh(self):
return type(self).get(self._pk_expr())

View File

@ -22,7 +22,7 @@ from vorta.utils import (
is_system_tray_available,
)
from vorta.views.partials.loading_button import LoadingButton
from vorta.views.utils import get_colored_icon
from vorta.views.utils import extract_profile_name, get_colored_icon
from .about_tab import AboutTab
from .archive_tab import ArchiveTab
@ -135,13 +135,22 @@ class MainWindow(MainWindowBase, MainWindowUI):
self.profileDeleteButton.setIcon(get_colored_icon('minus'))
self.miscButton.setIcon(get_colored_icon('settings_wheel'))
def set_progress(self, text=''):
self.progressText.setText(text)
self.progressText.repaint()
def set_progress(self, profile_id, text=''):
profile = BackupProfileModel.get_by_id(profile_id)
profile.last_status = text
profile.save()
if profile.name == self.current_profile.name:
self.progressText.setText(text)
self.progressText.repaint()
def set_log(self, text=''):
self.logText.setText(text)
self.logText.repaint()
profile = extract_profile_name(text)
if profile == self.current_profile.name:
self.logText.setText(text)
self.logText.repaint()
else:
self.logText.setText('')
self.logText.repaint()
def _toggle_buttons(self, create_enabled=True):
if create_enabled:
@ -188,6 +197,8 @@ class MainWindow(MainWindowBase, MainWindowUI):
SettingsModel.key == 'previous_profile_id'
).execute()
self.archiveTab.toggle_compact_button_visibility()
self.app.backup_progress_event.emit(self.current_profile.id, self.current_profile.last_status)
self.app.backup_log_event.emit("", {})
def profile_clicked_action(self):
if self.miscWidget.isVisible():

View File

@ -1,5 +1,6 @@
import json
import os
import re
import sys
from PyQt6.QtGui import QIcon, QImage, QPixmap
@ -49,3 +50,14 @@ def get_exclusion_presets():
'tags': preset['tags'],
}
return allPresets
def extract_profile_name(text):
pattern = r'\[([^]]+)\]'
match = re.search(pattern, text)
if match:
return match.group(1)
else:
return None