2018-11-01 16:53:41 +00:00
|
|
|
from datetime import timedelta
|
2018-11-04 08:23:17 +00:00
|
|
|
import copy
|
2018-10-29 05:12:45 +00:00
|
|
|
from PyQt5 import uic
|
2018-10-27 17:24:34 +00:00
|
|
|
from PyQt5.QtWidgets import QFileDialog, QTableWidgetItem, QTableView, QHeaderView
|
|
|
|
|
2018-11-04 08:23:17 +00:00
|
|
|
from vorta.borg.prune import BorgPruneThread
|
|
|
|
from vorta.borg.list import BorgListThread
|
2018-11-04 15:37:46 +00:00
|
|
|
from vorta.borg.check import BorgCheckThread
|
|
|
|
from vorta.borg.mount import BorgMountThread
|
2018-11-17 11:36:44 +00:00
|
|
|
from vorta.utils import get_asset, keyring, pretty_bytes, choose_folder_dialog
|
2018-11-04 08:23:17 +00:00
|
|
|
from vorta.models import BackupProfileMixin
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-10-29 05:49:25 +00:00
|
|
|
uifile = get_asset('UI/snapshottab.ui')
|
2018-11-04 15:37:46 +00:00
|
|
|
SnapshotUI, SnapshotBase = uic.loadUiType(uifile, from_imports=True, import_from='vorta.views')
|
2018-10-27 17:24:34 +00:00
|
|
|
|
|
|
|
|
2018-10-31 16:09:01 +00:00
|
|
|
class SnapshotTab(SnapshotBase, SnapshotUI, BackupProfileMixin):
|
2018-11-04 08:23:17 +00:00
|
|
|
prune_intervals = ['hour', 'day', 'week', 'month', 'year']
|
|
|
|
|
2018-10-27 17:24:34 +00:00
|
|
|
def __init__(self, parent=None):
|
|
|
|
super().__init__(parent)
|
|
|
|
self.setupUi(parent)
|
|
|
|
|
|
|
|
header = self.snapshotTable.horizontalHeader()
|
|
|
|
header.setVisible(True)
|
2018-11-02 06:06:25 +00:00
|
|
|
header.setSectionResizeMode(0, QHeaderView.ResizeToContents)
|
2018-10-27 17:24:34 +00:00
|
|
|
header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
|
2018-11-01 16:53:41 +00:00
|
|
|
header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
|
2018-11-02 06:06:25 +00:00
|
|
|
header.setSectionResizeMode(3, QHeaderView.Stretch)
|
2018-10-27 17:24:34 +00:00
|
|
|
|
|
|
|
self.snapshotTable.setSelectionBehavior(QTableView.SelectRows)
|
|
|
|
self.snapshotTable.setEditTriggers(QTableView.NoEditTriggers)
|
|
|
|
|
2018-11-04 08:23:17 +00:00
|
|
|
# Populate pruning options from database
|
|
|
|
for i in self.prune_intervals:
|
|
|
|
getattr(self, f'prune_{i}').setValue(getattr(self.profile(), f'prune_{i}'))
|
|
|
|
getattr(self, f'prune_{i}').valueChanged.connect(self.save_prune_setting)
|
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
self.mountButton.clicked.connect(self.mount_action)
|
2018-11-04 08:23:17 +00:00
|
|
|
self.listButton.clicked.connect(self.list_action)
|
|
|
|
self.pruneButton.clicked.connect(self.prune_action)
|
2018-11-04 15:37:46 +00:00
|
|
|
self.checkButton.clicked.connect(self.check_action)
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-17 08:51:53 +00:00
|
|
|
self.populate_from_profile()
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
def _set_status(self, text):
|
2018-10-28 15:40:38 +00:00
|
|
|
self.mountErrors.setText(text)
|
|
|
|
self.mountErrors.repaint()
|
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
def _toggle_all_buttons(self, enabled=True):
|
|
|
|
self.checkButton.setEnabled(enabled)
|
|
|
|
self.listButton.setEnabled(enabled)
|
|
|
|
self.pruneButton.setEnabled(enabled)
|
|
|
|
self.mountButton.setEnabled(enabled)
|
|
|
|
|
2018-11-17 08:51:53 +00:00
|
|
|
def populate_from_profile(self):
|
|
|
|
profile = self.profile()
|
|
|
|
if profile.repo:
|
|
|
|
self.currentRepoLabel.setText(profile.repo.url)
|
|
|
|
snapshots = [s for s in profile.repo.snapshots.select()]
|
2018-10-27 17:24:34 +00:00
|
|
|
|
|
|
|
for row, snapshot in enumerate(snapshots):
|
|
|
|
self.snapshotTable.insertRow(row)
|
2018-11-02 06:06:25 +00:00
|
|
|
formatted_time = snapshot.time.strftime('%Y-%m-%d %H:%M')
|
|
|
|
self.snapshotTable.setItem(row, 0, QTableWidgetItem(formatted_time))
|
2018-11-01 16:53:41 +00:00
|
|
|
self.snapshotTable.setItem(row, 1, QTableWidgetItem(pretty_bytes(snapshot.size)))
|
|
|
|
if snapshot.duration:
|
|
|
|
formatted_duration = str(timedelta(seconds=round(snapshot.duration)))
|
|
|
|
else:
|
|
|
|
formatted_duration = 'N/A'
|
|
|
|
self.snapshotTable.setItem(row, 2, QTableWidgetItem(formatted_duration))
|
2018-11-02 06:06:25 +00:00
|
|
|
self.snapshotTable.setItem(row, 3, QTableWidgetItem(snapshot.name))
|
2018-10-27 17:24:34 +00:00
|
|
|
self.snapshotTable.setRowCount(len(snapshots))
|
2018-11-17 08:51:53 +00:00
|
|
|
self._toggle_all_buttons(enabled=True)
|
2018-11-02 11:14:54 +00:00
|
|
|
else:
|
|
|
|
self.snapshotTable.setRowCount(0)
|
2018-11-17 08:51:53 +00:00
|
|
|
self.currentRepoLabel.setText('N/A')
|
|
|
|
self._toggle_all_buttons(enabled=False)
|
2018-11-04 15:37:46 +00:00
|
|
|
|
|
|
|
def check_action(self):
|
|
|
|
params = BorgCheckThread.prepare(self.profile())
|
|
|
|
if params['ok']:
|
|
|
|
thread = BorgCheckThread(params['cmd'], params, parent=self)
|
|
|
|
thread.updated.connect(self._set_status)
|
|
|
|
thread.result.connect(self.check_result)
|
|
|
|
self._toggle_all_buttons(False)
|
|
|
|
thread.start()
|
|
|
|
|
|
|
|
def check_result(self, result):
|
|
|
|
if result['returncode'] == 0:
|
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
|
2018-11-04 08:23:17 +00:00
|
|
|
def prune_action(self):
|
2018-11-04 15:37:46 +00:00
|
|
|
params = BorgPruneThread.prepare(self.profile())
|
2018-11-04 08:23:17 +00:00
|
|
|
if params['ok']:
|
|
|
|
thread = BorgPruneThread(params['cmd'], params, parent=self)
|
2018-11-04 15:37:46 +00:00
|
|
|
thread.updated.connect(self._set_status)
|
2018-11-04 08:23:17 +00:00
|
|
|
thread.result.connect(self.prune_result)
|
2018-11-04 15:37:46 +00:00
|
|
|
self._toggle_all_buttons(False)
|
2018-11-04 08:23:17 +00:00
|
|
|
thread.start()
|
|
|
|
|
|
|
|
def prune_result(self, result):
|
|
|
|
if result['returncode'] == 0:
|
2018-11-04 15:37:46 +00:00
|
|
|
self._set_status('Pruning finished.')
|
2018-11-04 08:23:17 +00:00
|
|
|
self.list_action()
|
|
|
|
else:
|
2018-11-04 15:37:46 +00:00
|
|
|
self._toggle_all_buttons(True)
|
2018-11-04 08:23:17 +00:00
|
|
|
|
|
|
|
def list_action(self):
|
2018-11-04 15:37:46 +00:00
|
|
|
params = BorgListThread.prepare(self.profile())
|
2018-11-04 08:23:17 +00:00
|
|
|
if params['ok']:
|
|
|
|
thread = BorgListThread(params['cmd'], params, parent=self)
|
2018-11-04 15:37:46 +00:00
|
|
|
thread.updated.connect(self._set_status)
|
2018-11-04 08:23:17 +00:00
|
|
|
thread.result.connect(self.list_result)
|
2018-11-04 15:37:46 +00:00
|
|
|
self._toggle_all_buttons(False)
|
2018-11-04 08:23:17 +00:00
|
|
|
thread.start()
|
|
|
|
|
|
|
|
def list_result(self, result):
|
2018-11-04 15:37:46 +00:00
|
|
|
self._toggle_all_buttons(True)
|
2018-11-04 08:23:17 +00:00
|
|
|
if result['returncode'] == 0:
|
2018-11-04 15:37:46 +00:00
|
|
|
self._set_status('Refreshed snapshots.')
|
2018-11-17 08:51:53 +00:00
|
|
|
self.populate_from_profile()
|
2018-11-04 08:23:17 +00:00
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
def mount_action(self):
|
2018-11-04 08:23:17 +00:00
|
|
|
profile = self.profile()
|
2018-11-04 15:37:46 +00:00
|
|
|
params = BorgMountThread.prepare(profile)
|
2018-11-13 00:12:17 +00:00
|
|
|
if not params['ok']:
|
|
|
|
self._set_status(params['message'])
|
|
|
|
return
|
|
|
|
|
|
|
|
# Conditions are met (borg binary available, etc)
|
2018-10-27 17:24:34 +00:00
|
|
|
row_selected = self.snapshotTable.selectionModel().selectedRows()
|
|
|
|
if row_selected:
|
2018-11-02 06:06:25 +00:00
|
|
|
snapshot_cell = self.snapshotTable.item(row_selected[0].row(), 3)
|
2018-10-27 17:24:34 +00:00
|
|
|
if snapshot_cell:
|
|
|
|
snapshot_name = snapshot_cell.text()
|
2018-11-04 15:37:46 +00:00
|
|
|
params['cmd'][-1] += f'::{snapshot_name}'
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-20 00:50:52 +00:00
|
|
|
def receive():
|
|
|
|
dir = dialog.selectedFiles()
|
|
|
|
if dir:
|
|
|
|
params['cmd'].append(dir)
|
|
|
|
if params['ok']:
|
|
|
|
self._toggle_all_buttons(False)
|
|
|
|
thread = BorgMountThread(params['cmd'], params, parent=self)
|
|
|
|
thread.updated.connect(self.mountErrors.setText)
|
|
|
|
thread.result.connect(self.mount_result)
|
|
|
|
thread.start()
|
|
|
|
|
|
|
|
dialog = choose_folder_dialog(self, "Choose Mount Point")
|
|
|
|
dialog.open(receive)
|
|
|
|
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
def mount_result(self, result):
|
|
|
|
self._toggle_all_buttons(True)
|
2018-10-27 17:24:34 +00:00
|
|
|
if result['returncode'] == 0:
|
2018-11-04 15:37:46 +00:00
|
|
|
self._set_status('Mounted successfully.')
|
2018-11-01 16:53:41 +00:00
|
|
|
|
2018-11-04 08:23:17 +00:00
|
|
|
def save_prune_setting(self, new_value):
|
|
|
|
profile = self.profile()
|
|
|
|
for i in self.prune_intervals:
|
|
|
|
setattr(profile, f'prune_{i}', getattr(self, f'prune_{i}').value())
|
|
|
|
profile.save()
|