2019-01-23 21:34:08 +01:00
|
|
|
import os
|
2019-01-26 11:25:26 +01:00
|
|
|
import sys
|
2019-01-23 21:34:08 +01:00
|
|
|
|
|
|
|
from PyQt5 import uic
|
|
|
|
from PyQt5.QtCore import QCoreApplication
|
2019-02-02 14:54:37 +01:00
|
|
|
from PyQt5.QtWidgets import QMainWindow, QFileSystemModel, QFileDialog
|
2019-01-23 21:34:08 +01:00
|
|
|
|
|
|
|
from config import Config
|
2019-02-02 14:54:37 +01:00
|
|
|
from helper import BorgException, show_error, convert_size, open_path
|
2019-02-02 11:27:38 +01:00
|
|
|
import borg_interface as borg
|
2019-02-02 14:54:37 +01:00
|
|
|
from progress import ProgressDialog
|
2019-01-23 21:34:08 +01:00
|
|
|
|
|
|
|
|
|
|
|
class MainWindow(QMainWindow):
|
2019-01-27 14:49:31 +01:00
|
|
|
"""The main window of the application. It provides the various functions to
|
|
|
|
control BorgBackup."""
|
2019-01-23 21:34:08 +01:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(MainWindow, self).__init__(*args, **kwargs)
|
|
|
|
QCoreApplication.setApplicationName("borg-qt")
|
2019-01-27 14:49:31 +01:00
|
|
|
|
|
|
|
# Load the UI file to get the dialogs layout.
|
2019-01-23 21:34:08 +01:00
|
|
|
dir_path = os.path.dirname(os.path.realpath(__file__))
|
|
|
|
ui_path = os.path.join(dir_path + '/static/UI/MainWindow.ui')
|
|
|
|
uic.loadUi(ui_path, self)
|
2019-01-27 14:49:31 +01:00
|
|
|
|
|
|
|
# Set the window title after the UI has been loaded. Otherwise it gets
|
|
|
|
# overwritten.
|
2019-01-26 10:38:30 +01:00
|
|
|
self.setWindowTitle("Borg-Qt")
|
2019-01-23 21:34:08 +01:00
|
|
|
|
2019-01-27 14:49:31 +01:00
|
|
|
# Create a Config object for storing the configuration.
|
2019-01-23 21:34:08 +01:00
|
|
|
self.config = Config()
|
|
|
|
|
2019-02-02 11:27:38 +01:00
|
|
|
# File tree
|
|
|
|
model = QFileSystemModel()
|
|
|
|
# model.setRootPath('/')
|
|
|
|
model.setRootPath(os.getenv('HOME'))
|
|
|
|
self.treeview_files.setModel(model)
|
|
|
|
self.treeview_files.expandAll()
|
|
|
|
self.treeview_files.setIndentation(20)
|
|
|
|
self.treeview_files.setColumnHidden(1, True)
|
|
|
|
self.treeview_files.setColumnHidden(2, True)
|
|
|
|
self.treeview_files.setColumnHidden(3, True)
|
|
|
|
# return the clicking on an item in the tree
|
|
|
|
self.treeview_files.clicked.connect(self.get_selected_path)
|
|
|
|
|
|
|
|
self.list_archive.setSortingEnabled(True)
|
|
|
|
|
2019-01-27 14:49:31 +01:00
|
|
|
# Connecting actions and buttons.
|
2019-01-23 21:34:08 +01:00
|
|
|
self.action_settings.triggered.connect(self.show_settings)
|
2019-02-02 11:27:38 +01:00
|
|
|
self.action_backup.triggered.connect(self.create_backup)
|
2019-02-02 14:54:37 +01:00
|
|
|
self.action_restore.triggered.connect(self.restore_backup)
|
2019-01-23 21:34:08 +01:00
|
|
|
|
2019-01-26 11:25:26 +01:00
|
|
|
def start(self):
|
2019-01-27 14:49:31 +01:00
|
|
|
"""This method is intendet to be used only once at the application
|
|
|
|
start. It reads the configuration file and sets the required
|
|
|
|
environment variables."""
|
2019-01-26 11:25:26 +01:00
|
|
|
try:
|
|
|
|
self.config.read()
|
|
|
|
self.config._set_environment_variables()
|
2019-02-02 11:27:38 +01:00
|
|
|
self._update_archives()
|
|
|
|
self._update_repository_stats()
|
2019-01-26 11:25:26 +01:00
|
|
|
except BorgException as e:
|
|
|
|
show_error(e)
|
|
|
|
sys.exit(1)
|
|
|
|
|
2019-01-23 21:34:08 +01:00
|
|
|
def show_settings(self):
|
2019-01-27 14:49:31 +01:00
|
|
|
"""Display the settings dialog."""
|
2019-01-23 21:34:08 +01:00
|
|
|
self.config.set_form_values()
|
|
|
|
self.config.exec_()
|
2019-02-02 11:27:38 +01:00
|
|
|
|
|
|
|
def get_selected_path(self, signal):
|
|
|
|
"""returns the path of the item selected in the file tree."""
|
|
|
|
self.src_path = self.treeview_files.model().filePath(signal)
|
|
|
|
|
|
|
|
def _check_path(self):
|
|
|
|
message = ("Please select a file or directory "
|
|
|
|
"before creating a backup.")
|
|
|
|
if not hasattr(self, 'src_path'):
|
|
|
|
raise BorgException(message)
|
|
|
|
|
|
|
|
def create_backup(self):
|
|
|
|
"""Creates a backup of the selected item in the treeview."""
|
|
|
|
try:
|
|
|
|
self._check_path()
|
2019-02-02 14:54:37 +01:00
|
|
|
thread = borg.BackupThread([self.src_path],
|
|
|
|
excludes=self.config.excludes,
|
|
|
|
prefix=self.config.prefix)
|
|
|
|
dialog = ProgressDialog(thread)
|
|
|
|
dialog.label_info.setText("creating a backup.")
|
|
|
|
dialog.exec_()
|
2019-02-02 11:27:38 +01:00
|
|
|
self.update_archives()
|
|
|
|
self.update_repository_stats()
|
|
|
|
except BorgException as e:
|
|
|
|
show_error(e)
|
|
|
|
|
2019-02-02 14:54:37 +01:00
|
|
|
def _get_target_path(self):
|
|
|
|
dlg = QFileDialog
|
|
|
|
dlg.DirectoryOnly
|
|
|
|
folder_name = str(dlg.getExistingDirectory(
|
|
|
|
self, "Select Directory", os.getenv('HOME')))
|
|
|
|
return folder_name
|
|
|
|
|
|
|
|
def restore_backup(self):
|
|
|
|
"""Restores a selected backup to the given path."""
|
|
|
|
target_path = self._get_target_path()
|
|
|
|
if target_path:
|
|
|
|
archive_name = self.list_archive.currentItem().text()
|
|
|
|
restore_path = os.path.join(target_path, archive_name)
|
|
|
|
try:
|
|
|
|
thread = borg.RestoreThread(archive_name, restore_path)
|
|
|
|
dialog = ProgressDialog(thread)
|
|
|
|
dialog.label_info.setText("restoring a backup.")
|
|
|
|
dialog.exec_()
|
|
|
|
open_path(restore_path)
|
|
|
|
except BorgException as e:
|
|
|
|
show_error(e)
|
|
|
|
|
2019-02-02 11:27:38 +01:00
|
|
|
def _update_archives(self):
|
|
|
|
"""Lists all the archive names in the UI."""
|
|
|
|
self.list_archive.clear()
|
|
|
|
archive_names = []
|
|
|
|
for archive in borg.get_archives():
|
|
|
|
archive_names.append(archive['name'])
|
|
|
|
self.list_archive.addItems(archive_names)
|
|
|
|
|
|
|
|
def update_archives(self):
|
|
|
|
"""Lists all the archive names in the UI."""
|
|
|
|
try:
|
|
|
|
self._update_archives()
|
|
|
|
except BorgException as e:
|
|
|
|
show_error(e)
|
|
|
|
|
|
|
|
def _update_repository_stats(self):
|
|
|
|
stats = borg.get_repository_stats()
|
|
|
|
self.label_repo_original_size.setText(
|
|
|
|
"Original Size: "
|
|
|
|
+ convert_size(stats['total_size']))
|
|
|
|
|
|
|
|
self.label_repo_compressed_size.setText(
|
|
|
|
"Compressed Size: "
|
|
|
|
+ convert_size(stats['total_csize']))
|
|
|
|
|
|
|
|
self.label_repo_deduplicated_size.setText(
|
|
|
|
"Deduplicated Size: "
|
|
|
|
+ convert_size(stats['unique_csize']))
|
|
|
|
|
|
|
|
def update_repository_stats(self):
|
|
|
|
try:
|
|
|
|
self._update_repository_stats()
|
|
|
|
except BorgException as e:
|
|
|
|
show_error(e)
|