2022-03-24 06:27:07 +00:00
|
|
|
import logging
|
2019-01-21 10:44:01 +00:00
|
|
|
import os.path
|
2018-11-22 01:05:54 +00:00
|
|
|
import sys
|
2018-11-01 16:53:41 +00:00
|
|
|
from datetime import timedelta
|
2022-03-24 06:27:07 +00:00
|
|
|
from typing import Dict
|
2019-07-04 19:17:09 +00:00
|
|
|
|
|
|
|
from PyQt5 import QtCore, uic
|
2022-03-24 06:27:07 +00:00
|
|
|
from PyQt5.QtCore import QMimeData, QPoint, Qt, pyqtSlot
|
|
|
|
from PyQt5.QtGui import QDesktopServices, QKeySequence
|
|
|
|
from PyQt5.QtWidgets import (QApplication, QHeaderView, QInputDialog, QLayout,
|
|
|
|
QMenu, QMessageBox, QShortcut, QTableView,
|
|
|
|
QTableWidgetItem, QWidget)
|
2021-10-04 11:31:41 +00:00
|
|
|
|
|
|
|
from vorta.borg.check import BorgCheckJob
|
2022-02-21 17:23:56 +00:00
|
|
|
from vorta.borg.compact import BorgCompactJob
|
2021-10-04 11:31:41 +00:00
|
|
|
from vorta.borg.delete import BorgDeleteJob
|
|
|
|
from vorta.borg.diff import BorgDiffJob
|
|
|
|
from vorta.borg.extract import BorgExtractJob
|
2022-03-24 06:27:07 +00:00
|
|
|
from vorta.borg.info_archive import BorgInfoArchiveJob
|
2021-10-04 11:31:41 +00:00
|
|
|
from vorta.borg.list_archive import BorgListArchiveJob
|
|
|
|
from vorta.borg.list_repo import BorgListRepoJob
|
|
|
|
from vorta.borg.mount import BorgMountJob
|
|
|
|
from vorta.borg.prune import BorgPruneJob
|
|
|
|
from vorta.borg.rename import BorgRenameJob
|
2022-03-24 06:27:07 +00:00
|
|
|
from vorta.borg.umount import BorgUmountJob
|
2019-02-19 13:42:19 +00:00
|
|
|
from vorta.i18n import trans_late
|
2021-11-17 09:14:11 +00:00
|
|
|
from vorta.store.models import ArchiveModel, BackupProfileMixin
|
2019-07-04 19:17:09 +00:00
|
|
|
from vorta.utils import (choose_file_dialog, format_archive_name, get_asset,
|
|
|
|
get_mount_points, pretty_bytes)
|
|
|
|
from vorta.views.diff_dialog import DiffDialog
|
|
|
|
from vorta.views.diff_result import DiffResult
|
|
|
|
from vorta.views.extract_dialog import ExtractDialog
|
2022-03-24 06:27:07 +00:00
|
|
|
from vorta.views.source_tab import SizeItem
|
2020-05-31 11:29:26 +00:00
|
|
|
from vorta.views.utils import get_colored_icon
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-22 01:18:12 +00:00
|
|
|
uifile = get_asset('UI/archivetab.ui')
|
2020-05-31 11:29:26 +00:00
|
|
|
ArchiveTabUI, ArchiveTabBase = uic.loadUiType(uifile)
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2022-03-24 06:27:07 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-22 01:18:12 +00:00
|
|
|
class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
|
2018-11-04 08:23:17 +00:00
|
|
|
prune_intervals = ['hour', 'day', 'week', 'month', 'year']
|
|
|
|
|
2020-10-30 05:17:24 +00:00
|
|
|
def __init__(self, parent=None, app=None):
|
2022-03-24 06:27:07 +00:00
|
|
|
"""Init."""
|
2018-10-27 17:24:34 +00:00
|
|
|
super().__init__(parent)
|
|
|
|
self.setupUi(parent)
|
2019-01-21 10:44:01 +00:00
|
|
|
self.mount_points = {}
|
|
|
|
self.menu = None
|
2020-10-30 05:17:24 +00:00
|
|
|
self.app = app
|
2018-12-14 08:03:26 +00:00
|
|
|
self.toolBox.setCurrentIndex(0)
|
2022-03-24 06:27:07 +00:00
|
|
|
self.repoactions_enabled = True
|
|
|
|
|
|
|
|
#: Tooltip dict to save the tooltips set in the designer
|
|
|
|
self.tooltip_dict: Dict[QWidget, str] = {}
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-22 01:18:12 +00:00
|
|
|
header = self.archiveTable.horizontalHeader()
|
2018-10-27 17:24:34 +00:00
|
|
|
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)
|
2019-01-28 00:41:42 +00:00
|
|
|
header.setSectionResizeMode(3, QHeaderView.Interactive)
|
2019-01-21 10:44:01 +00:00
|
|
|
header.setSectionResizeMode(4, QHeaderView.Stretch)
|
2018-11-22 05:48:16 +00:00
|
|
|
header.setStretchLastSection(True)
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-22 01:05:54 +00:00
|
|
|
if sys.platform != 'darwin':
|
|
|
|
self._set_status('') # Set platform-specific hints.
|
|
|
|
|
2018-11-22 01:18:12 +00:00
|
|
|
self.archiveTable.setSelectionBehavior(QTableView.SelectRows)
|
2019-01-21 10:44:01 +00:00
|
|
|
self.archiveTable.setSelectionMode(QTableView.SingleSelection)
|
2018-11-22 01:18:12 +00:00
|
|
|
self.archiveTable.setEditTriggers(QTableView.NoEditTriggers)
|
2019-01-28 00:41:42 +00:00
|
|
|
self.archiveTable.setWordWrap(False)
|
|
|
|
self.archiveTable.setTextElideMode(QtCore.Qt.ElideLeft)
|
2018-11-22 07:03:19 +00:00
|
|
|
self.archiveTable.setAlternatingRowColors(True)
|
2019-01-21 10:44:01 +00:00
|
|
|
self.archiveTable.cellDoubleClicked.connect(self.cell_double_clicked)
|
2019-10-02 04:05:40 +00:00
|
|
|
self.archiveTable.setSortingEnabled(True)
|
2022-03-24 06:27:07 +00:00
|
|
|
self.archiveTable.setContextMenuPolicy(
|
|
|
|
Qt.ContextMenuPolicy.CustomContextMenu)
|
|
|
|
self.archiveTable.customContextMenuRequested.connect(
|
|
|
|
self.archiveitem_contextmenu)
|
|
|
|
|
|
|
|
# shortcuts
|
|
|
|
shortcut_copy = QShortcut(QKeySequence.StandardKey.Copy,
|
|
|
|
self.archiveTable)
|
|
|
|
shortcut_copy.activated.connect(self.archive_copy)
|
|
|
|
|
|
|
|
# connect archive actions
|
|
|
|
self.bMount.clicked.connect(self.bmount_clicked)
|
|
|
|
self.bRefreshArchive.clicked.connect(self.refresh_archive_info)
|
|
|
|
self.bRename.clicked.connect(self.rename_action)
|
|
|
|
self.bDelete.clicked.connect(self.delete_action)
|
|
|
|
self.bExtract.clicked.connect(self.extract_action)
|
2022-02-21 17:23:56 +00:00
|
|
|
self.compactButton.clicked.connect(self.compact_action)
|
2021-02-18 01:44:10 +00:00
|
|
|
|
2022-03-24 06:27:07 +00:00
|
|
|
# other signals
|
|
|
|
self.bList.clicked.connect(self.refresh_archive_list)
|
|
|
|
self.bPrune.clicked.connect(self.prune_action)
|
|
|
|
self.bCheck.clicked.connect(self.check_action)
|
|
|
|
self.bDiff.clicked.connect(self.diff_action)
|
|
|
|
|
|
|
|
self.archiveTable.itemSelectionChanged.connect(self.on_selection_change)
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-12-14 08:03:26 +00:00
|
|
|
self.archiveNameTemplate.textChanged.connect(
|
|
|
|
lambda tpl, key='new_archive_name': self.save_archive_template(tpl, key))
|
|
|
|
self.prunePrefixTemplate.textChanged.connect(
|
|
|
|
lambda tpl, key='prune_prefix': self.save_archive_template(tpl, key))
|
|
|
|
|
2018-11-17 08:51:53 +00:00
|
|
|
self.populate_from_profile()
|
2020-03-23 06:20:09 +00:00
|
|
|
self.selected_archives = None
|
2021-02-18 01:44:10 +00:00
|
|
|
self.set_icons()
|
2020-03-23 06:20:09 +00:00
|
|
|
|
2020-05-31 11:29:26 +00:00
|
|
|
def set_icons(self):
|
2021-02-18 01:44:10 +00:00
|
|
|
"Used when changing between light- and dark mode"
|
2022-03-24 06:27:07 +00:00
|
|
|
self.bCheck.setIcon(get_colored_icon('check-circle'))
|
|
|
|
self.bDiff.setIcon(get_colored_icon('stream-solid'))
|
|
|
|
self.bPrune.setIcon(get_colored_icon('cut'))
|
|
|
|
self.bList.setIcon(get_colored_icon('refresh'))
|
2022-02-21 17:23:56 +00:00
|
|
|
self.compactButton.setIcon(get_colored_icon('broom-solid'))
|
2020-05-31 11:29:26 +00:00
|
|
|
self.toolBox.setItemIcon(0, get_colored_icon('tasks'))
|
|
|
|
self.toolBox.setItemIcon(1, get_colored_icon('cut'))
|
2022-03-24 06:27:07 +00:00
|
|
|
self.bRefreshArchive.setIcon(get_colored_icon('refresh'))
|
|
|
|
self.bRename.setIcon(get_colored_icon('edit'))
|
|
|
|
self.bDelete.setIcon(get_colored_icon('trash'))
|
|
|
|
self.bExtract.setIcon(get_colored_icon('cloud-download'))
|
|
|
|
|
|
|
|
self.bmount_refresh()
|
|
|
|
|
|
|
|
@pyqtSlot(QPoint)
|
|
|
|
def archiveitem_contextmenu(self, pos: QPoint):
|
|
|
|
# index under cursor
|
|
|
|
index = self.archiveTable.indexAt(pos)
|
|
|
|
if not index.isValid():
|
|
|
|
return # popup only for items
|
|
|
|
|
|
|
|
menu = QMenu(self.archiveTable)
|
|
|
|
menu.setEnabled(self.repoactions_enabled)
|
|
|
|
|
|
|
|
menu.addAction(get_colored_icon('copy'), self.tr("Copy"),
|
|
|
|
lambda: self.archive_copy(index=index))
|
|
|
|
menu.addSeparator()
|
|
|
|
|
|
|
|
menu.addAction(self.bRefreshArchive.icon(),
|
|
|
|
self.bRefreshArchive.text(),
|
|
|
|
self.refresh_archive_info)
|
|
|
|
menu.addAction(self.bMount.icon(), self.bMount.text(),
|
|
|
|
self.bmount_clicked)
|
|
|
|
menu.addAction(self.bExtract.icon(), self.bExtract.text(),
|
|
|
|
self.extract_action)
|
|
|
|
menu.addAction(self.bRename.icon(), self.bRename.text(),
|
|
|
|
self.rename_action)
|
|
|
|
menu.addAction(self.bDelete.icon(), self.bDelete.text(),
|
|
|
|
self.delete_action)
|
|
|
|
|
|
|
|
menu.popup(self.archiveTable.viewport().mapToGlobal(pos))
|
2020-05-31 11:29:26 +00:00
|
|
|
|
2021-01-20 05:07:32 +00:00
|
|
|
def cancel_action(self):
|
|
|
|
self._set_status(self.tr("Action cancelled."))
|
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
|
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):
|
2022-03-24 06:27:07 +00:00
|
|
|
"""
|
|
|
|
Set all the buttons in the archive panel to the given state.
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
enabled : bool, optional
|
|
|
|
The enabled state, by default True
|
|
|
|
"""
|
|
|
|
self.repoactions_enabled = enabled
|
|
|
|
|
|
|
|
for button in [self.bCheck, self.bList, self.bPrune,
|
|
|
|
self.bDiff, self.fArchiveActions]:
|
2018-11-27 11:33:16 +00:00
|
|
|
button.setEnabled(enabled)
|
|
|
|
button.repaint()
|
2018-11-04 15:37:46 +00:00
|
|
|
|
2022-03-24 06:27:07 +00:00
|
|
|
# Restore states
|
|
|
|
self.on_selection_change()
|
2021-02-18 01:44:10 +00:00
|
|
|
|
2018-11-17 08:51:53 +00:00
|
|
|
def populate_from_profile(self):
|
2018-11-27 11:33:16 +00:00
|
|
|
"""Populate archive list and prune settings from profile."""
|
2018-11-17 08:51:53 +00:00
|
|
|
profile = self.profile()
|
2018-11-20 04:06:09 +00:00
|
|
|
if profile.repo is not None:
|
2019-01-21 10:44:01 +00:00
|
|
|
self.mount_points = get_mount_points(profile.repo.url)
|
2019-01-20 03:50:10 +00:00
|
|
|
self.toolBox.setItemText(0, self.tr('Archives for %s') % profile.repo.url)
|
2018-11-22 05:48:16 +00:00
|
|
|
archives = [s for s in profile.repo.archives.select().order_by(ArchiveModel.time.desc())]
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2021-02-11 06:19:37 +00:00
|
|
|
sorting = self.archiveTable.isSortingEnabled()
|
|
|
|
self.archiveTable.setSortingEnabled(False)
|
2018-11-22 05:48:16 +00:00
|
|
|
for row, archive in enumerate(archives):
|
2018-11-22 01:18:12 +00:00
|
|
|
self.archiveTable.insertRow(row)
|
2018-11-22 05:48:16 +00:00
|
|
|
|
|
|
|
formatted_time = archive.time.strftime('%Y-%m-%d %H:%M')
|
2018-11-22 01:18:12 +00:00
|
|
|
self.archiveTable.setItem(row, 0, QTableWidgetItem(formatted_time))
|
2020-11-29 00:51:24 +00:00
|
|
|
self.archiveTable.setItem(row, 1, SizeItem(pretty_bytes(archive.size)))
|
2018-11-22 05:48:16 +00:00
|
|
|
if archive.duration is not None:
|
|
|
|
formatted_duration = str(timedelta(seconds=round(archive.duration)))
|
2018-11-01 16:53:41 +00:00
|
|
|
else:
|
2018-11-22 05:48:16 +00:00
|
|
|
formatted_duration = ''
|
2019-01-21 10:44:01 +00:00
|
|
|
|
2018-11-22 01:18:12 +00:00
|
|
|
self.archiveTable.setItem(row, 2, QTableWidgetItem(formatted_duration))
|
2019-01-21 10:44:01 +00:00
|
|
|
|
|
|
|
mount_point = self.mount_points.get(archive.name)
|
|
|
|
if mount_point is not None:
|
2019-01-28 00:41:42 +00:00
|
|
|
item = QTableWidgetItem(mount_point)
|
2019-01-21 10:44:01 +00:00
|
|
|
self.archiveTable.setItem(row, 3, item)
|
|
|
|
|
|
|
|
self.archiveTable.setItem(row, 4, QTableWidgetItem(archive.name))
|
|
|
|
|
2018-11-22 05:48:16 +00:00
|
|
|
self.archiveTable.setRowCount(len(archives))
|
2021-02-11 06:19:37 +00:00
|
|
|
self.archiveTable.setSortingEnabled(sorting)
|
2018-11-27 11:33:16 +00:00
|
|
|
item = self.archiveTable.item(0, 0)
|
|
|
|
self.archiveTable.scrollToItem(item)
|
2022-03-24 06:27:07 +00:00
|
|
|
|
|
|
|
self.archiveTable.selectionModel().clearSelection()
|
2018-11-17 08:51:53 +00:00
|
|
|
self._toggle_all_buttons(enabled=True)
|
2018-11-02 11:14:54 +00:00
|
|
|
else:
|
2019-01-21 10:44:01 +00:00
|
|
|
self.mount_points = {}
|
2018-11-22 01:18:12 +00:00
|
|
|
self.archiveTable.setRowCount(0)
|
2019-01-20 03:50:10 +00:00
|
|
|
self.toolBox.setItemText(0, self.tr('Archives'))
|
2018-11-17 08:51:53 +00:00
|
|
|
self._toggle_all_buttons(enabled=False)
|
2018-11-04 15:37:46 +00:00
|
|
|
|
2018-12-14 08:03:26 +00:00
|
|
|
self.archiveNameTemplate.setText(profile.new_archive_name)
|
|
|
|
self.prunePrefixTemplate.setText(profile.prune_prefix)
|
|
|
|
|
2019-08-21 12:54:00 +00:00
|
|
|
# Populate pruning options from database
|
|
|
|
profile = self.profile()
|
|
|
|
for i in self.prune_intervals:
|
|
|
|
getattr(self, f'prune_{i}').setValue(getattr(profile, f'prune_{i}'))
|
|
|
|
getattr(self, f'prune_{i}').valueChanged.connect(self.save_prune_setting)
|
|
|
|
self.prune_keep_within.setText(profile.prune_keep_within)
|
|
|
|
self.prune_keep_within.editingFinished.connect(self.save_prune_setting)
|
|
|
|
|
2022-03-24 06:27:07 +00:00
|
|
|
@pyqtSlot()
|
|
|
|
def on_selection_change(self):
|
|
|
|
"""
|
|
|
|
React to a change of the selection of the archiveTableView.
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
selected : QItemSelection
|
|
|
|
The new selection.
|
|
|
|
deselected : QItemSelection
|
|
|
|
The previous selection.
|
|
|
|
"""
|
|
|
|
indexes = self.archiveTable.selectionModel().selectedRows()
|
|
|
|
|
|
|
|
if len(indexes) == 1:
|
|
|
|
# Enable archive actions
|
|
|
|
self.fArchiveActions.setEnabled(True)
|
|
|
|
|
|
|
|
layout: QLayout = self.fArchiveActions.layout()
|
|
|
|
for index in range(layout.count()):
|
|
|
|
widget = layout.itemAt(index).widget()
|
|
|
|
widget.setToolTip(self.tooltip_dict.get(widget, ""))
|
|
|
|
else:
|
|
|
|
# too few or too many selected.
|
|
|
|
self.fArchiveActions.setEnabled(False)
|
|
|
|
|
|
|
|
layout: QLayout = self.fArchiveActions.layout()
|
|
|
|
for index in range(layout.count()):
|
|
|
|
widget = layout.itemAt(index).widget()
|
|
|
|
tooltip = widget.toolTip()
|
|
|
|
|
|
|
|
tooltip = self.tooltip_dict.setdefault(widget, tooltip)
|
|
|
|
widget.setToolTip(
|
|
|
|
tooltip + " " + self.tr("(Select exactly one archive)"))
|
|
|
|
|
|
|
|
def archive_copy(self, index=None):
|
|
|
|
"""
|
|
|
|
Copy an archive name to the clipboard.
|
|
|
|
|
|
|
|
Copies the first selected archive if no index is specified.
|
|
|
|
"""
|
|
|
|
if index is None:
|
|
|
|
indexes = self.archiveTable.selectionModel().selectedRows()
|
|
|
|
|
|
|
|
if not indexes:
|
|
|
|
return
|
|
|
|
|
|
|
|
index = indexes[0]
|
|
|
|
|
|
|
|
archive_name = self.archiveTable.item(index.row(), 4).text()
|
|
|
|
|
|
|
|
data = QMimeData()
|
|
|
|
data.setText(archive_name)
|
|
|
|
|
|
|
|
QApplication.clipboard().setMimeData(data)
|
|
|
|
|
2018-12-14 08:03:26 +00:00
|
|
|
def save_archive_template(self, tpl, key):
|
|
|
|
profile = self.profile()
|
|
|
|
try:
|
2019-01-20 03:50:10 +00:00
|
|
|
preview = self.tr('Preview: %s') % format_archive_name(profile, tpl)
|
2018-12-14 08:03:26 +00:00
|
|
|
setattr(profile, key, tpl)
|
|
|
|
profile.save()
|
|
|
|
except Exception:
|
2019-01-20 03:50:10 +00:00
|
|
|
preview = self.tr('Error in archive name template.')
|
2018-12-14 08:03:26 +00:00
|
|
|
|
|
|
|
if key == 'new_archive_name':
|
|
|
|
self.archiveNamePreview.setText(preview)
|
|
|
|
else:
|
|
|
|
self.prunePrefixPreview.setText(preview)
|
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
def check_action(self):
|
2021-10-04 11:31:41 +00:00
|
|
|
params = BorgCheckJob.prepare(self.profile())
|
2018-11-23 13:33:31 +00:00
|
|
|
if not params['ok']:
|
2019-02-19 13:42:19 +00:00
|
|
|
self._set_status(params['message'])
|
2018-11-23 13:33:31 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
# Conditions are met (borg binary available, etc)
|
|
|
|
row_selected = self.archiveTable.selectionModel().selectedRows()
|
|
|
|
if row_selected:
|
2019-01-21 10:44:01 +00:00
|
|
|
archive_cell = self.archiveTable.item(row_selected[0].row(), 4)
|
2019-01-20 03:50:10 +00:00
|
|
|
if archive_cell:
|
|
|
|
archive_name = archive_cell.text()
|
|
|
|
params['cmd'][-1] += f'::{archive_name}'
|
2018-11-23 13:33:31 +00:00
|
|
|
|
2021-10-04 11:31:41 +00:00
|
|
|
job = BorgCheckJob(params['cmd'], params, self.profile().repo.id)
|
|
|
|
job.updated.connect(self._set_status)
|
|
|
|
job.result.connect(self.check_result)
|
2018-11-23 13:33:31 +00:00
|
|
|
self._toggle_all_buttons(False)
|
2021-11-12 07:05:31 +00:00
|
|
|
self.app.jobs_manager.add_job(job)
|
2018-11-04 15:37:46 +00:00
|
|
|
|
|
|
|
def check_result(self, result):
|
|
|
|
if result['returncode'] == 0:
|
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
|
2022-02-21 17:23:56 +00:00
|
|
|
def compact_action(self):
|
|
|
|
params = BorgCompactJob.prepare(self.profile())
|
|
|
|
if params['ok']:
|
|
|
|
job = BorgCompactJob(params['cmd'], params, self.profile().repo.id)
|
|
|
|
job.updated.connect(self._set_status)
|
|
|
|
job.result.connect(self.compact_result)
|
|
|
|
self._toggle_all_buttons(False)
|
|
|
|
self.app.jobs_manager.add_job(job)
|
|
|
|
else:
|
|
|
|
self._set_status(params['message'])
|
|
|
|
|
|
|
|
def compact_result(self, result):
|
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
|
2018-11-04 08:23:17 +00:00
|
|
|
def prune_action(self):
|
2021-10-04 11:31:41 +00:00
|
|
|
params = BorgPruneJob.prepare(self.profile())
|
2018-11-04 08:23:17 +00:00
|
|
|
if params['ok']:
|
2021-10-04 11:31:41 +00:00
|
|
|
job = BorgPruneJob(params['cmd'], params, self.profile().repo.id)
|
|
|
|
job.updated.connect(self._set_status)
|
|
|
|
job.result.connect(self.prune_result)
|
2018-11-04 15:37:46 +00:00
|
|
|
self._toggle_all_buttons(False)
|
2021-11-12 07:05:31 +00:00
|
|
|
self.app.jobs_manager.add_job(job)
|
2021-02-18 01:44:10 +00:00
|
|
|
else:
|
|
|
|
self._set_status(params['message'])
|
2018-11-04 08:23:17 +00:00
|
|
|
|
|
|
|
def prune_result(self, result):
|
|
|
|
if result['returncode'] == 0:
|
2019-01-20 03:50:10 +00:00
|
|
|
self._set_status(self.tr('Pruning finished.'))
|
2022-03-24 06:27:07 +00:00
|
|
|
self.refresh_archive_list()
|
2018-11-04 08:23:17 +00:00
|
|
|
else:
|
2018-11-04 15:37:46 +00:00
|
|
|
self._toggle_all_buttons(True)
|
2018-11-04 08:23:17 +00:00
|
|
|
|
2022-03-24 06:27:07 +00:00
|
|
|
def refresh_archive_list(self):
|
2021-10-04 11:31:41 +00:00
|
|
|
params = BorgListRepoJob.prepare(self.profile())
|
2018-11-04 08:23:17 +00:00
|
|
|
if params['ok']:
|
2021-10-04 11:31:41 +00:00
|
|
|
job = BorgListRepoJob(params['cmd'], params, self.profile().repo.id)
|
|
|
|
job.updated.connect(self._set_status)
|
|
|
|
job.result.connect(self.list_result)
|
2018-11-04 15:37:46 +00:00
|
|
|
self._toggle_all_buttons(False)
|
2021-11-12 07:05:31 +00:00
|
|
|
self.app.jobs_manager.add_job(job)
|
2021-02-18 01:44:10 +00:00
|
|
|
else:
|
|
|
|
self._set_status(params['message'])
|
2018-11-04 08:23:17 +00:00
|
|
|
|
|
|
|
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:
|
2019-01-20 03:50:10 +00:00
|
|
|
self._set_status(self.tr('Refreshed archives.'))
|
2018-11-17 08:51:53 +00:00
|
|
|
self.populate_from_profile()
|
2021-02-23 02:12:09 +00:00
|
|
|
|
2022-03-24 06:27:07 +00:00
|
|
|
def refresh_archive_info(self):
|
2021-02-23 02:12:09 +00:00
|
|
|
archive_name = self.selected_archive_name()
|
|
|
|
if archive_name is not None:
|
2021-10-04 11:31:41 +00:00
|
|
|
params = BorgInfoArchiveJob.prepare(self.profile(), archive_name)
|
2021-02-23 02:12:09 +00:00
|
|
|
if params['ok']:
|
2021-10-04 11:31:41 +00:00
|
|
|
job = BorgInfoArchiveJob(params['cmd'], params, self.profile().repo.id)
|
|
|
|
job.updated.connect(self._set_status)
|
2022-03-24 06:27:07 +00:00
|
|
|
job.result.connect(self.info_result)
|
2021-02-23 02:12:09 +00:00
|
|
|
self._toggle_all_buttons(False)
|
2021-11-12 07:05:31 +00:00
|
|
|
self.app.jobs_manager.add_job(job)
|
2021-02-23 02:12:09 +00:00
|
|
|
|
2022-03-24 06:27:07 +00:00
|
|
|
def info_result(self, result):
|
2021-02-23 02:12:09 +00:00
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
if result['returncode'] == 0:
|
|
|
|
self._set_status(self.tr('Refreshed archive.'))
|
|
|
|
self.populate_from_profile()
|
2018-11-04 08:23:17 +00:00
|
|
|
|
2019-01-21 10:44:01 +00:00
|
|
|
def selected_archive_name(self):
|
|
|
|
row_selected = self.archiveTable.selectionModel().selectedRows()
|
|
|
|
if row_selected:
|
|
|
|
archive_cell = self.archiveTable.item(row_selected[0].row(), 4)
|
|
|
|
if archive_cell:
|
|
|
|
return archive_cell.text()
|
|
|
|
return None
|
|
|
|
|
2022-03-24 06:27:07 +00:00
|
|
|
def bmount_clicked(self):
|
|
|
|
"""
|
|
|
|
Handle `bMount` being clicked.
|
|
|
|
|
|
|
|
Mount or umount the current archive depending on its current state.
|
|
|
|
"""
|
|
|
|
archive_name = self.selected_archive_name()
|
|
|
|
|
|
|
|
if not archive_name:
|
|
|
|
logger.warning("Archive name of selection is empty.")
|
|
|
|
return
|
|
|
|
|
|
|
|
if archive_name in self.mount_points:
|
|
|
|
self.umount_action()
|
|
|
|
else:
|
|
|
|
self.mount_action()
|
|
|
|
|
|
|
|
def bmount_refresh(self):
|
|
|
|
"""
|
|
|
|
Update tooltip and state of `bMount`.
|
|
|
|
|
|
|
|
The new state depends on the mount status of the current archive.
|
|
|
|
This also updates the icon of the button.
|
|
|
|
"""
|
|
|
|
archive_name = self.selected_archive_name()
|
|
|
|
|
|
|
|
if archive_name in self.mount_points:
|
|
|
|
self.bMount.setText(self.tr("Unmount"))
|
|
|
|
self.bMount.setIcon(get_colored_icon('eject'))
|
|
|
|
else:
|
|
|
|
self.bMount.setText(self.tr("Mount…"))
|
|
|
|
self.bMount.setIcon(get_colored_icon('folder-open'))
|
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
def mount_action(self):
|
2018-11-04 08:23:17 +00:00
|
|
|
profile = self.profile()
|
2021-10-04 11:31:41 +00:00
|
|
|
params = BorgMountJob.prepare(profile)
|
2018-11-13 00:12:17 +00:00
|
|
|
if not params['ok']:
|
2019-02-19 13:42:19 +00:00
|
|
|
self._set_status(params['message'])
|
2018-11-13 00:12:17 +00:00
|
|
|
return
|
|
|
|
|
2019-01-21 10:44:01 +00:00
|
|
|
archive_name = self.selected_archive_name()
|
2022-03-24 06:27:07 +00:00
|
|
|
|
|
|
|
if not archive_name:
|
|
|
|
# Conditions aren't met (borg binary available, etc)
|
|
|
|
logger.debug('Archive name empty.')
|
|
|
|
return
|
|
|
|
|
|
|
|
params['cmd'][-1] += f'::{archive_name}'
|
|
|
|
params['current_archive'] = archive_name
|
2018-10-27 17:24:34 +00:00
|
|
|
|
2018-11-20 00:50:52 +00:00
|
|
|
def receive():
|
2018-11-22 04:06:10 +00:00
|
|
|
mount_point = dialog.selectedFiles()
|
|
|
|
if mount_point:
|
|
|
|
params['cmd'].append(mount_point[0])
|
2019-04-07 07:28:02 +00:00
|
|
|
if params.get('current_archive', False):
|
|
|
|
self.mount_points[params['current_archive']] = mount_point[0]
|
2018-11-20 00:50:52 +00:00
|
|
|
if params['ok']:
|
|
|
|
self._toggle_all_buttons(False)
|
2021-10-04 11:31:41 +00:00
|
|
|
job = BorgMountJob(params['cmd'], params, self.profile().repo.id)
|
|
|
|
job.updated.connect(self.mountErrors.setText)
|
|
|
|
job.result.connect(self.mount_result)
|
2021-11-12 07:05:31 +00:00
|
|
|
self.app.jobs_manager.add_job(job)
|
2018-11-20 00:50:52 +00:00
|
|
|
|
2019-01-21 10:44:01 +00:00
|
|
|
dialog = choose_file_dialog(self, self.tr("Choose Mount Point"), want_folder=True)
|
2018-11-20 00:50:52 +00:00
|
|
|
dialog.open(receive)
|
|
|
|
|
2018-11-04 15:37:46 +00:00
|
|
|
def mount_result(self, result):
|
2018-10-27 17:24:34 +00:00
|
|
|
if result['returncode'] == 0:
|
2019-01-20 03:50:10 +00:00
|
|
|
self._set_status(self.tr('Mounted successfully.'))
|
2019-04-07 07:28:02 +00:00
|
|
|
if result['params'].get('current_archive'):
|
|
|
|
archive_name = result['params']['current_archive']
|
|
|
|
row = self.row_of_archive(archive_name)
|
|
|
|
item = QTableWidgetItem(result['cmd'][-1])
|
|
|
|
self.archiveTable.setItem(row, 3, item)
|
2018-11-22 04:06:10 +00:00
|
|
|
|
2022-03-24 06:27:07 +00:00
|
|
|
# update button
|
|
|
|
self.bmount_refresh()
|
|
|
|
|
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
|
2018-11-22 04:06:10 +00:00
|
|
|
def umount_action(self):
|
2019-01-21 10:44:01 +00:00
|
|
|
archive_name = self.selected_archive_name()
|
|
|
|
mount_point = self.mount_points.get(archive_name)
|
|
|
|
|
|
|
|
if mount_point is not None:
|
2018-11-22 04:06:10 +00:00
|
|
|
profile = self.profile()
|
2021-10-04 11:31:41 +00:00
|
|
|
params = BorgUmountJob.prepare(profile)
|
2018-11-22 04:06:10 +00:00
|
|
|
if not params['ok']:
|
2019-02-19 13:42:19 +00:00
|
|
|
self._set_status(params['message'])
|
2018-11-22 04:06:10 +00:00
|
|
|
return
|
|
|
|
|
2019-01-21 10:44:01 +00:00
|
|
|
params['current_archive'] = archive_name
|
|
|
|
|
|
|
|
if os.path.normpath(mount_point) in params['active_mount_points']:
|
|
|
|
params['cmd'].append(mount_point)
|
2021-10-04 11:31:41 +00:00
|
|
|
job = BorgUmountJob(params['cmd'], params, self.profile().repo.id)
|
|
|
|
job.updated.connect(self.mountErrors.setText)
|
|
|
|
job.result.connect(self.umount_result)
|
2021-11-12 07:05:31 +00:00
|
|
|
self.app.jobs_manager.add_job(job)
|
2018-11-22 04:06:10 +00:00
|
|
|
else:
|
2019-01-21 10:44:01 +00:00
|
|
|
self._set_status(self.tr('Mount point not active.'))
|
2018-11-22 04:06:10 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
def umount_result(self, result):
|
|
|
|
self._toggle_all_buttons(True)
|
2020-12-16 03:10:38 +00:00
|
|
|
archive_name = result['params']['current_archive']
|
2018-11-22 04:06:10 +00:00
|
|
|
if result['returncode'] == 0:
|
2019-01-20 03:50:10 +00:00
|
|
|
self._set_status(self.tr('Un-mounted successfully.'))
|
2019-01-21 10:44:01 +00:00
|
|
|
del self.mount_points[archive_name]
|
|
|
|
row = self.row_of_archive(archive_name)
|
|
|
|
item = QTableWidgetItem('')
|
|
|
|
self.archiveTable.setItem(row, 3, item)
|
2022-03-24 06:27:07 +00:00
|
|
|
|
|
|
|
# update button
|
|
|
|
self.bmount_refresh()
|
2020-12-16 03:10:38 +00:00
|
|
|
else:
|
2022-03-24 06:27:07 +00:00
|
|
|
self._set_status(
|
|
|
|
self.tr('Unmounting failed. Make sure no programs are using {}')
|
|
|
|
.format(self.mount_points.get(archive_name)))
|
2018-11-01 16:53:41 +00:00
|
|
|
|
2018-11-24 02:01:50 +00:00
|
|
|
def save_prune_setting(self, new_value=None):
|
2018-11-04 08:23:17 +00:00
|
|
|
profile = self.profile()
|
|
|
|
for i in self.prune_intervals:
|
|
|
|
setattr(profile, f'prune_{i}', getattr(self, f'prune_{i}').value())
|
2018-11-24 02:01:50 +00:00
|
|
|
profile.prune_keep_within = self.prune_keep_within.text()
|
2018-11-04 08:23:17 +00:00
|
|
|
profile.save()
|
2018-11-22 10:25:22 +00:00
|
|
|
|
2022-03-24 06:27:07 +00:00
|
|
|
def extract_action(self):
|
2018-11-27 11:33:16 +00:00
|
|
|
profile = self.profile()
|
|
|
|
|
|
|
|
row_selected = self.archiveTable.selectionModel().selectedRows()
|
|
|
|
if row_selected:
|
2019-01-21 10:44:01 +00:00
|
|
|
archive_cell = self.archiveTable.item(row_selected[0].row(), 4)
|
2018-11-27 11:33:16 +00:00
|
|
|
if archive_cell:
|
|
|
|
archive_name = archive_cell.text()
|
2021-10-04 11:31:41 +00:00
|
|
|
params = BorgListArchiveJob.prepare(profile, archive_name)
|
2018-11-27 11:33:16 +00:00
|
|
|
|
|
|
|
if not params['ok']:
|
2019-02-19 13:42:19 +00:00
|
|
|
self._set_status(params['message'])
|
2018-11-27 11:33:16 +00:00
|
|
|
return
|
|
|
|
self._set_status('')
|
|
|
|
self._toggle_all_buttons(False)
|
|
|
|
|
2021-10-04 11:31:41 +00:00
|
|
|
job = BorgListArchiveJob(params['cmd'], params, self.profile().repo.id)
|
|
|
|
job.updated.connect(self.mountErrors.setText)
|
2022-03-24 06:27:07 +00:00
|
|
|
job.result.connect(self.extract_list_result)
|
2021-11-12 07:05:31 +00:00
|
|
|
self.app.jobs_manager.add_job(job)
|
2021-10-04 11:31:41 +00:00
|
|
|
return job
|
2018-11-27 11:33:16 +00:00
|
|
|
else:
|
2019-01-20 03:50:10 +00:00
|
|
|
self._set_status(self.tr('Select an archive to restore first.'))
|
2018-11-27 11:33:16 +00:00
|
|
|
|
2022-03-24 06:27:07 +00:00
|
|
|
def extract_list_result(self, result):
|
2018-11-27 11:33:16 +00:00
|
|
|
self._set_status('')
|
|
|
|
if result['returncode'] == 0:
|
2020-11-20 00:46:09 +00:00
|
|
|
def process_result():
|
2018-11-27 11:33:16 +00:00
|
|
|
def receive():
|
|
|
|
extraction_folder = dialog.selectedFiles()
|
|
|
|
if extraction_folder:
|
2021-10-04 11:31:41 +00:00
|
|
|
params = BorgExtractJob.prepare(
|
2018-11-27 11:33:16 +00:00
|
|
|
self.profile(), archive.name, window.selected, extraction_folder[0])
|
|
|
|
if params['ok']:
|
|
|
|
self._toggle_all_buttons(False)
|
2021-10-04 11:31:41 +00:00
|
|
|
job = BorgExtractJob(params['cmd'], params, self.profile().repo.id)
|
|
|
|
job.updated.connect(self.mountErrors.setText)
|
|
|
|
job.result.connect(self.extract_archive_result)
|
2021-11-12 07:05:31 +00:00
|
|
|
self.app.jobs_manager.add_job(job)
|
2018-11-27 11:33:16 +00:00
|
|
|
else:
|
2019-02-19 13:42:19 +00:00
|
|
|
self._set_status(params['message'])
|
2018-11-27 11:33:16 +00:00
|
|
|
|
2019-01-21 10:44:01 +00:00
|
|
|
dialog = choose_file_dialog(self, self.tr("Choose Extraction Point"), want_folder=True)
|
2018-11-27 11:33:16 +00:00
|
|
|
dialog.open(receive)
|
|
|
|
|
2020-11-20 00:46:09 +00:00
|
|
|
archive = ArchiveModel.get(name=result['params']['archive_name'])
|
|
|
|
window = ExtractDialog(result['data'], archive)
|
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
window.setParent(self, QtCore.Qt.Sheet)
|
|
|
|
self._window = window # for testing
|
|
|
|
window.show()
|
|
|
|
window.accepted.connect(process_result)
|
|
|
|
|
2018-11-27 11:33:16 +00:00
|
|
|
def extract_archive_result(self, result):
|
|
|
|
self._toggle_all_buttons(True)
|
2019-01-21 10:44:01 +00:00
|
|
|
|
|
|
|
def cell_double_clicked(self, row, column):
|
|
|
|
if column == 3:
|
|
|
|
archive_name = self.selected_archive_name()
|
|
|
|
if not archive_name:
|
|
|
|
return
|
|
|
|
|
|
|
|
mount_point = self.mount_points.get(archive_name)
|
|
|
|
|
|
|
|
if mount_point is not None:
|
|
|
|
QDesktopServices.openUrl(QtCore.QUrl(f'file:///{mount_point}'))
|
|
|
|
|
|
|
|
def row_of_archive(self, archive_name):
|
|
|
|
items = self.archiveTable.findItems(archive_name, QtCore.Qt.MatchExactly)
|
|
|
|
rows = [item.row() for item in items if item.column() == 4]
|
|
|
|
return rows[0] if rows else None
|
2019-01-24 00:36:44 +00:00
|
|
|
|
2019-02-02 02:01:09 +00:00
|
|
|
def confirm_dialog(self, title, text):
|
2019-02-02 04:29:33 +00:00
|
|
|
msg = QMessageBox()
|
|
|
|
msg.setIcon(QMessageBox.Information)
|
|
|
|
msg.setText(text)
|
|
|
|
msg.setWindowTitle(title)
|
|
|
|
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
|
|
|
|
msg.button(msg.Yes).setText(self.tr("Yes"))
|
|
|
|
msg.button(msg.Cancel).setText(self.tr("Cancel"))
|
|
|
|
return msg.exec_() == QMessageBox.Yes
|
2019-02-02 02:01:09 +00:00
|
|
|
|
2019-01-24 00:36:44 +00:00
|
|
|
def delete_action(self):
|
2021-10-04 11:31:41 +00:00
|
|
|
# Since this function modify the UI, we can't put the whole function in a JobQUeue.
|
|
|
|
|
|
|
|
params = BorgDeleteJob.prepare(self.profile())
|
2019-01-24 00:36:44 +00:00
|
|
|
if not params['ok']:
|
2019-02-19 13:42:19 +00:00
|
|
|
self._set_status(params['message'])
|
2019-01-24 00:36:44 +00:00
|
|
|
return
|
|
|
|
|
2020-11-20 00:46:09 +00:00
|
|
|
self.archive_name = self.selected_archive_name()
|
|
|
|
if self.archive_name is not None:
|
2019-02-02 04:29:33 +00:00
|
|
|
if not self.confirm_dialog(trans_late('ArchiveTab', "Confirm deletion"),
|
|
|
|
trans_late('ArchiveTab', "Are you sure you want to delete the archive?")):
|
2019-02-02 02:01:09 +00:00
|
|
|
return
|
2020-11-20 00:46:09 +00:00
|
|
|
params['cmd'][-1] += f'::{self.archive_name}'
|
2021-10-04 11:31:41 +00:00
|
|
|
job = BorgDeleteJob(params['cmd'], params, self.profile().repo.id)
|
|
|
|
job.updated.connect(self._set_status)
|
|
|
|
job.result.connect(self.delete_result)
|
2019-01-24 00:36:44 +00:00
|
|
|
self._toggle_all_buttons(False)
|
2021-11-12 07:05:31 +00:00
|
|
|
self.app.jobs_manager.add_job(job)
|
2021-10-04 11:31:41 +00:00
|
|
|
|
2019-01-24 00:36:44 +00:00
|
|
|
else:
|
2019-02-02 02:01:09 +00:00
|
|
|
self._set_status(self.tr("No archive selected"))
|
2019-01-24 00:36:44 +00:00
|
|
|
|
|
|
|
def delete_result(self, result):
|
|
|
|
if result['returncode'] == 0:
|
|
|
|
self._set_status(self.tr('Archive deleted.'))
|
2020-11-20 00:46:09 +00:00
|
|
|
deleted_row = self.archiveTable.findItems(self.archive_name, QtCore.Qt.MatchExactly)[0].row()
|
|
|
|
self.archiveTable.removeRow(deleted_row)
|
|
|
|
ArchiveModel.get(name=self.archive_name).delete_instance()
|
|
|
|
del self.archive_name
|
2019-01-24 00:36:44 +00:00
|
|
|
else:
|
|
|
|
self._toggle_all_buttons(True)
|
2019-07-04 19:17:09 +00:00
|
|
|
|
|
|
|
def diff_action(self):
|
2020-11-20 00:46:09 +00:00
|
|
|
def process_result():
|
2020-03-23 06:20:09 +00:00
|
|
|
if window.selected_archives:
|
|
|
|
self.selected_archives = window.selected_archives
|
|
|
|
archive_cell_newer = self.archiveTable.item(self.selected_archives[0], 4)
|
|
|
|
archive_cell_older = self.archiveTable.item(self.selected_archives[1], 4)
|
2019-07-04 19:17:09 +00:00
|
|
|
if archive_cell_older and archive_cell_newer:
|
|
|
|
archive_name_newer = archive_cell_newer.text()
|
|
|
|
archive_name_older = archive_cell_older.text()
|
|
|
|
|
2021-10-04 11:31:41 +00:00
|
|
|
params = BorgDiffJob.prepare(profile, archive_name_older, archive_name_newer)
|
2019-07-04 19:17:09 +00:00
|
|
|
|
|
|
|
if params['ok']:
|
|
|
|
self._toggle_all_buttons(False)
|
2021-10-04 11:31:41 +00:00
|
|
|
job = BorgDiffJob(params['cmd'], params, self.profile().repo.id)
|
|
|
|
job.updated.connect(self.mountErrors.setText)
|
|
|
|
job.result.connect(self.list_diff_result)
|
2021-11-12 07:05:31 +00:00
|
|
|
self.app.jobs_manager.add_job(job)
|
2019-07-04 19:17:09 +00:00
|
|
|
else:
|
|
|
|
self._set_status(params['message'])
|
|
|
|
|
2020-11-20 00:46:09 +00:00
|
|
|
profile = self.profile()
|
|
|
|
|
|
|
|
window = DiffDialog(self.archiveTable)
|
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
window.setParent(self, QtCore.Qt.Sheet)
|
|
|
|
self._window = window # for testing
|
|
|
|
window.show()
|
|
|
|
window.accepted.connect(process_result)
|
|
|
|
|
2019-07-04 19:17:09 +00:00
|
|
|
def list_diff_result(self, result):
|
|
|
|
self._set_status('')
|
|
|
|
if result['returncode'] == 0:
|
|
|
|
archive_newer = ArchiveModel.get(name=result['params']['archive_name_newer'])
|
|
|
|
archive_older = ArchiveModel.get(name=result['params']['archive_name_older'])
|
2021-03-29 23:47:27 +00:00
|
|
|
window = DiffResult(result['data'], archive_newer, archive_older, result['params']['json_lines'])
|
2019-07-04 19:17:09 +00:00
|
|
|
self._toggle_all_buttons(True)
|
|
|
|
window.setParent(self, QtCore.Qt.Sheet)
|
2020-03-23 06:20:09 +00:00
|
|
|
self._resultwindow = window # for testing
|
2019-07-04 19:17:09 +00:00
|
|
|
window.show()
|
2021-02-18 01:44:10 +00:00
|
|
|
|
|
|
|
def rename_action(self):
|
|
|
|
profile = self.profile()
|
2021-10-04 11:31:41 +00:00
|
|
|
params = BorgRenameJob.prepare(profile)
|
2021-02-18 01:44:10 +00:00
|
|
|
if not params['ok']:
|
|
|
|
self._set_status(params['message'])
|
|
|
|
return
|
|
|
|
|
|
|
|
archive_name = self.selected_archive_name()
|
|
|
|
if archive_name is not None:
|
|
|
|
new_name, finished = QInputDialog.getText(
|
|
|
|
self,
|
|
|
|
self.tr("Change name"),
|
|
|
|
self.tr("New archive name:"),
|
|
|
|
text=archive_name)
|
|
|
|
|
|
|
|
if not finished:
|
|
|
|
return
|
|
|
|
|
|
|
|
if not new_name:
|
|
|
|
self._set_status(self.tr('Archive name cannot be blank.'))
|
|
|
|
return
|
|
|
|
|
|
|
|
new_name_exists = ArchiveModel.get_or_none(name=new_name, repo=profile.repo)
|
|
|
|
if new_name_exists is not None:
|
|
|
|
self._set_status(self.tr('An archive with this name already exists.'))
|
|
|
|
return
|
|
|
|
|
|
|
|
params['cmd'][-1] += f'::{archive_name}'
|
|
|
|
params['cmd'].append(new_name)
|
2021-10-04 11:31:41 +00:00
|
|
|
job = BorgRenameJob(params['cmd'], params, self.profile().repo.id)
|
|
|
|
job.updated.connect(self._set_status)
|
|
|
|
job.result.connect(self.rename_result)
|
2021-02-18 01:44:10 +00:00
|
|
|
self._toggle_all_buttons(False)
|
2021-11-12 07:05:31 +00:00
|
|
|
self.app.jobs_manager.add_job(job)
|
2021-02-18 01:44:10 +00:00
|
|
|
else:
|
|
|
|
self._set_status(self.tr("No archive selected"))
|
|
|
|
|
|
|
|
def rename_result(self, result):
|
|
|
|
if result['returncode'] == 0:
|
|
|
|
self._set_status(self.tr('Archive renamed.'))
|
|
|
|
self.populate_from_profile()
|
|
|
|
else:
|
|
|
|
self._toggle_all_buttons(True)
|