Rewrite of borg diff core (#373)

- It now heavily relies on regex. This was done in order to make the code more stable and easier to maintain.
- Share common code for file tree view between extract and diff.
This commit is contained in:
Julian 2020-03-23 07:20:09 +01:00 committed by GitHub
parent 4a8d6e8768
commit 3b6c5f2d3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 408 additions and 433 deletions

View File

@ -76,6 +76,8 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
self.populate_from_profile()
self.selected_archives = None
def _set_status(self, text):
self.mountErrors.setText(text)
self.mountErrors.repaint()
@ -429,9 +431,10 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
window.show()
if window.exec_():
selected_archives = window.selected_archives
archive_cell_newer = self.archiveTable.item(selected_archives[0], 4)
archive_cell_older = self.archiveTable.item(selected_archives[1], 4)
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)
if archive_cell_older and archive_cell_newer:
archive_name_newer = archive_cell_newer.text()
archive_name_older = archive_cell_older.text()
@ -457,5 +460,5 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
window = DiffResult(result['data'], archive_newer, archive_older)
self._toggle_all_buttons(True)
window.setParent(self, QtCore.Qt.Sheet)
self._window = window # for testing
self._resultwindow = window # for testing
window.show()

View File

@ -3,12 +3,11 @@ from PyQt5.QtWidgets import QHeaderView, QTableView, QTableWidgetItem
from vorta.utils import get_asset
uifile = get_asset('UI/diffdialog.ui')
uifile = get_asset("UI/diffdialog.ui")
DiffDialogUI, DiffDialogBase = uic.loadUiType(uifile)
class DiffDialog(DiffDialogBase, DiffDialogUI):
def __init__(self, archiveTable):
super().__init__()
self.setupUi(self)
@ -38,7 +37,7 @@ class DiffDialog(DiffDialogBase, DiffDialogUI):
text = archiveTable.item(row, column).text()
self.archiveTable.setItem(row, column, QTableWidgetItem(text))
except AttributeError:
self.archiveTable.setItem(row, column, QTableWidgetItem(''))
self.archiveTable.setItem(row, column, QTableWidgetItem(""))
self.diffButton.setEnabled(False)

View File

@ -1,34 +1,28 @@
import os
import re
from PyQt5 import uic
from PyQt5.QtCore import QAbstractItemModel, QModelIndex, Qt, QVariant
from PyQt5.QtCore import Qt, QVariant
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QHeaderView
from vorta.utils import (get_asset, get_dict_from_list, nested_dict,
pretty_bytes)
from vorta.utils import (get_asset, get_dict_from_list, nested_dict)
from vorta.views.tree_view import TreeModel
uifile = get_asset('UI/diffresult.ui')
DiffResultUI, DiffResultBase = uic.loadUiType(uifile)
files_with_attributes = None
nested_file_list = None
selected_files_folders = None
class DiffResult(DiffResultBase, DiffResultUI):
def __init__(self, fs_data, archive_newer, archive_older):
super().__init__()
self.setupUi(self)
global files_with_attributes, nested_file_list, selected_files_folders
# Clear global file lists
files_with_attributes = []
nested_file_list = nested_dict()
selected_files_folders = set()
def parse_line(line):
if line:
line_split = line.split()
else:
@ -36,59 +30,48 @@ class DiffResult(DiffResultBase, DiffResultUI):
if line_split[0] == 'added' or line_split[0] == 'removed':
change_type = line_split[0]
size = line_split[1]
unit = line_split[2]
if line_split[1] in ['directory', 'link']:
size = 0
full_path = re.search(r'^\w+ \w+ +(.*)', line).group(1)
else:
significand = line_split[1]
unit = line_split[2]
size = calc_size(significand, unit)
full_path = re.search(r'^\w+ +\S+ \w?B (.*)', line).group(1)
else:
change_type = "modified"
size = line_split[0]
unit = line_split[1]
# If present remove '+' or '-' sign at the front
if size[0] in ('+', '-'):
size = size[1:]
size_change = re.search(r' *[\+-]?(\d+\.*\d*) (\w?B) +[\+-]?.+\w?B ', line)
if size_change:
significand = size_change.group(1)
unit = size_change.group(2)
size = calc_size(significand, unit)
full_path_index = size_change.end(0)
else:
size = 0
if line_split[0].startswith("["):
size = 0
change_type = line[:line.find(line_split[3])]
full_path = line[line.find(line_split[3]):]
dir, name = os.path.split(full_path)
# add to nested dict of folders to find nested dirs.
d = get_dict_from_list(nested_file_list, full_path.split('/'))
elif line_split[1] not in ['directory', 'link']:
if unit == 'B':
size = int(size)
elif unit == 'kB':
size = int(float(size) * 10**3)
elif unit == 'MB':
size = int(float(size) * 10**6)
elif unit == 'GB':
size = int(float(size) * 10**9)
elif unit == 'TB':
size = int(float(size) * 10**12)
permission_change = re.search(r' *(\[.{24}\]) ', line)
if permission_change:
change_type = permission_change.group(1)
full_path_index = permission_change.end(0)
else:
change_type = "modified"
if change_type == 'added' or change_type == 'removed':
full_path = line[line.find(line_split[3]):]
elif change_type == "modified":
full_path = line[line.find(line_split[4]):]
if size_change and permission_change:
full_path_index = max(size_change.end(0), permission_change.end(0))
full_path = line[full_path_index:]
dir, name = os.path.split(full_path)
# add to nested dict of folders to find nested dirs.
d = get_dict_from_list(nested_file_list, dir.split('/'))
if name not in d:
d[name] = {}
else:
size = 0
full_path = line[line.find(line_split[2]):]
dir, name = os.path.split(full_path)
dir, name = os.path.split(full_path)
# add to nested dict of folders to find nested dirs.
d = get_dict_from_list(nested_file_list, full_path.split('/'))
# add to nested dict of folders to find nested dirs.
d = get_dict_from_list(nested_file_list, dir.split('/'))
if name not in d:
d[name] = {}
return size, change_type, name, dir
for l in fs_data.split('\n'):
files_with_attributes.append(parse_line(l))
model = TreeModel()
model = DiffTree(files_with_attributes, nested_file_list)
view = self.treeView
view.setAlternatingRowColors(True)
@ -103,113 +86,31 @@ class DiffResult(DiffResultBase, DiffResultUI):
self.archiveNameLabel_1.setText(f'{archive_newer.name}')
self.archiveNameLabel_2.setText(f'{archive_older.name}')
self.okButton.clicked.connect(self.accept)
self.selected = selected_files_folders
class FolderItem:
def __init__(self, path, name, modified, parent=None):
self.parentItem = parent
self.path = path
self.itemData = [name, modified]
self.childItems = []
# Pre-filter children
self._filtered_children = []
search_path = os.path.join(self.path, name)
if parent is None: # Find path for root folder
for root_folder in nested_file_list.keys():
self._filtered_children.append((0, '', root_folder, '', ))
else:
# This adds direct children.
self._filtered_children = [f for f in files_with_attributes if search_path == f[3]]
# Add nested folders.
for immediate_child in get_dict_from_list(nested_file_list, search_path.split('/')).keys():
if not [True for child in self._filtered_children if child[2] == immediate_child]:
self._filtered_children.append((0, '', immediate_child, search_path))
self.is_loaded = False
def load_children(self):
for child_item in self._filtered_children:
if child_item[0] > 0: # This is a file
self.childItems.append(FileItem(
name=child_item[2],
modified=child_item[1],
size=child_item[0],
parent=self))
else: # Folder
self.childItems.append(
FolderItem(
path=child_item[3],
name=child_item[2],
modified=child_item[1],
parent=self))
self.is_loaded = True
def child(self, row):
return self.childItems[row]
def childCount(self):
return len(self._filtered_children)
def columnCount(self):
return 3
def data(self, column):
if column <= 1:
return self.itemData[column]
else:
return None
def parent(self):
return self.parentItem
def row(self):
if self.parentItem:
return self.parentItem.childItems.index(self)
return 0
def calc_size(significand, unit):
if unit == 'B':
return int(significand)
elif unit == 'kB':
return int(float(significand) * 10**3)
elif unit == 'MB':
return int(float(significand) * 10**6)
elif unit == 'GB':
return int(float(significand) * 10**9)
elif unit == 'TB':
return int(float(significand) * 10**12)
class FileItem(FolderItem):
def __init__(self, name, modified, size, parent=None):
self.parentItem = parent
self.itemData = [name, modified, size]
def childCount(self):
return 0
def columnCount(self):
return 3
def data(self, column):
if column == 1:
return self.itemData[column]
elif column == 2:
return pretty_bytes(self.itemData[column])
elif column == 0:
return self.itemData[column]
def parent(self):
return self.parentItem
def row(self):
return self.parentItem.childItems.index(self)
class TreeModel(QAbstractItemModel):
column_names = ['Name', 'Modified', 'Size']
def __init__(self, parent=None):
super(TreeModel, self).__init__(parent)
self.rootItem = FolderItem(path='', name='', modified=None)
self.rootItem.load_children()
def columnCount(self, parent):
return 3
class DiffTree(TreeModel):
def __init__(
self,
files_with_attributes,
nested_file_list,
parent=None,
):
super().__init__(
files_with_attributes, nested_file_list, parent=parent
)
def data(self, index, role):
if not index.isValid():
@ -230,61 +131,7 @@ class TreeModel(QAbstractItemModel):
else:
return None
def canFetchMore(self, index):
if not index.isValid():
return False
item = index.internalPointer()
return not item.is_loaded
def fetchMore(self, index):
item = index.internalPointer()
item.load_children()
def flags(self, index):
if not index.isValid():
return Qt.NoItemFlags
return Qt.ItemIsEnabled
def headerData(self, section, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.column_names[section]
return None
def index(self, row, column, parent):
if not self.hasIndex(row, column, parent):
return QModelIndex()
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
childItem = parentItem.child(row)
if childItem:
return self.createIndex(row, column, childItem)
else:
return QModelIndex()
def parent(self, index):
if not index.isValid():
return QModelIndex()
childItem = index.internalPointer()
parentItem = childItem.parent()
if parentItem == self.rootItem:
return QModelIndex()
return self.createIndex(parentItem.row(), 0, parentItem)
def rowCount(self, parent):
if parent.column() > 0:
return 0
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
return parentItem.childCount()

View File

@ -4,50 +4,45 @@ import datetime
from collections import namedtuple
from PyQt5 import uic
from PyQt5.QtCore import QAbstractItemModel, QModelIndex, Qt
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QHeaderView
from vorta.utils import get_asset, pretty_bytes, get_dict_from_list, nested_dict
from vorta.utils import get_asset, get_dict_from_list, nested_dict
from vorta.views.tree_view import TreeModel
uifile = get_asset('UI/extractdialog.ui')
uifile = get_asset("UI/extractdialog.ui")
ExtractDialogUI, ExtractDialogBase = uic.loadUiType(uifile)
ISO_FORMAT = '%Y-%m-%dT%H:%M:%S.%f'
files_with_attributes = None
nested_file_list = None
selected_files_folders = None
ISO_FORMAT = "%Y-%m-%dT%H:%M:%S.%f"
class ExtractDialog(ExtractDialogBase, ExtractDialogUI):
def __init__(self, fs_data, archive):
super().__init__()
self.setupUi(self)
global files_with_attributes, nested_file_list, selected_files_folders
# Clear global file lists
files_with_attributes = []
nested_file_list = nested_dict()
selected_files_folders = set()
self.selected = set()
def parse_line(line):
size, modified, full_path = line.split('\t')
size, modified, full_path = line.split("\t")
size = int(size)
dir, name = os.path.split(full_path)
# add to nested dict of folders to find nested dirs.
d = get_dict_from_list(nested_file_list, dir.split('/'))
d = get_dict_from_list(nested_file_list, dir.split("/"))
if name not in d:
d[name] = {}
return size, modified, name, dir
for l in fs_data.split('\n'):
for l in fs_data.split("\n"):
try:
files_with_attributes.append(parse_line(l))
except ValueError:
pass
model = TreeModel()
model = ExtractTree(files_with_attributes, nested_file_list, self.selected)
view = self.treeView
view.setAlternatingRowColors(True)
@ -59,141 +54,22 @@ class ExtractDialog(ExtractDialogBase, ExtractDialogUI):
header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
header.setSectionResizeMode(0, QHeaderView.Stretch)
self.archiveNameLabel.setText(f'{archive.name}, {archive.time}')
self.archiveNameLabel.setText(f"{archive.name}, {archive.time}")
self.cancelButton.clicked.connect(self.close)
self.extractButton.clicked.connect(self.accept)
self.selected = selected_files_folders
class FolderItem:
def __init__(self, path, name, modified, parent=None):
self.parentItem = parent
self.path = path
self.itemData = [name, modified]
self.childItems = []
self.checkedState = False
# Pre-filter children
self._filtered_children = []
search_path = os.path.join(self.path, name)
if parent is None: # Find path for root folder
for root_folder in nested_file_list.keys():
self._filtered_children.append((0, '', root_folder, '', ))
else:
self.checkedState = parent.checkedState # If there is a parent, use its checked-status.
# This adds direct children.
self._filtered_children = [f for f in files_with_attributes if search_path == f[3]]
# Add nested folders.
for immediate_child in get_dict_from_list(nested_file_list, search_path.split('/')).keys():
if not [True for child in self._filtered_children if child[2] == immediate_child]:
self._filtered_children.append((0, '', immediate_child, search_path))
self.is_loaded = False
def load_children(self):
for child_item in self._filtered_children:
if child_item[0] > 0: # This is a file
self.childItems.append(FileItem(
name=child_item[2],
modified=child_item[1],
size=child_item[0],
parent=self))
else: # Folder
self.childItems.append(
FolderItem(
path=child_item[3],
name=child_item[2],
modified=child_item[1],
parent=self))
self.is_loaded = True
def setCheckedState(self, value):
if value == 2:
self.checkedState = True
selected_files_folders.add(
os.path.join(self.parentItem.path, self.parentItem.data(0), self.itemData[0]))
else:
self.checkedState = False
path_to_remove = os.path.join(self.parentItem.path, self.parentItem.data(0), self.itemData[0])
if path_to_remove in selected_files_folders:
selected_files_folders.remove(path_to_remove)
if hasattr(self, 'childItems'):
for child in self.childItems:
child.setCheckedState(value)
def getCheckedState(self):
if self.checkedState:
return Qt.Checked
else:
return Qt.Unchecked
def child(self, row):
return self.childItems[row]
def childCount(self):
return len(self._filtered_children)
def columnCount(self):
return 3
def data(self, column):
if column <= 1:
return self.itemData[column]
else:
return None
def parent(self):
return self.parentItem
def row(self):
if self.parentItem:
return self.parentItem.childItems.index(self)
return 0
class FileItem(FolderItem):
def __init__(self, name, modified, size, parent=None):
self.parentItem = parent
self.itemData = [name, modified, size] # dt.strptime(modified, ISO_FORMAT)
self.checkedState = parent.checkedState
def childCount(self):
return 0
def columnCount(self):
return 3
def data(self, column):
if column == 1:
return self.itemData[column] # .strftime('%Y-%m-%dT%H:%M')
elif column == 2:
return pretty_bytes(self.itemData[column])
elif column == 0:
return self.itemData[column]
def parent(self):
return self.parentItem
def row(self):
return self.parentItem.childItems.index(self)
class TreeModel(QAbstractItemModel):
column_names = ['Name', 'Modified', 'Size']
def __init__(self, parent=None):
super(TreeModel, self).__init__(parent)
self.rootItem = FolderItem(path='', name='', modified=None)
self.rootItem.load_children()
def columnCount(self, parent):
return 3
class ExtractTree(TreeModel):
def __init__(
self,
files_with_attributes,
nested_file_list,
selected_files_folders,
parent=None,
):
super().__init__(
files_with_attributes, nested_file_list, selected_files_folders, parent
)
def data(self, index, role):
if not index.isValid():
@ -208,86 +84,24 @@ class TreeModel(QAbstractItemModel):
else:
return None
def setData(self, index, value, role=Qt.EditRole):
if role == Qt.CheckStateRole:
item = index.internalPointer()
item.setCheckedState(value)
self.dataChanged.emit(QModelIndex(), QModelIndex(), [])
return True
def canFetchMore(self, index):
if not index.isValid():
return False
item = index.internalPointer()
return not item.is_loaded
def fetchMore(self, index):
item = index.internalPointer()
item.load_children()
def flags(self, index):
if not index.isValid():
return Qt.NoItemFlags
return Qt.ItemIsEnabled | Qt.ItemIsUserCheckable
def headerData(self, section, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.column_names[section]
return None
def index(self, row, column, parent):
if not self.hasIndex(row, column, parent):
return QModelIndex()
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
childItem = parentItem.child(row)
if childItem:
return self.createIndex(row, column, childItem)
else:
return QModelIndex()
def parent(self, index):
if not index.isValid():
return QModelIndex()
childItem = index.internalPointer()
parentItem = childItem.parent()
if parentItem == self.rootItem:
return QModelIndex()
return self.createIndex(parentItem.row(), 0, parentItem)
def rowCount(self, parent):
if parent.column() > 0:
return 0
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
return parentItem.childCount()
if __name__ == '__main__':
if __name__ == "__main__":
"""
For local testing:
borg list --progress --info --log-json --format="{size:8d}{TAB}{mtime}{TAB}{path}{NL}"
"""
FakeArchive = namedtuple('Archive', ['name', 'time'])
FakeArchive = namedtuple("Archive", ["name", "time"])
app = QApplication(sys.argv)
test_list = open('/Users/manu/Downloads/nyx2-list.txt').read()
test_list = open("/Users/manu/Downloads/nyx2-list.txt").read()
archive = FakeArchive('test-archive', datetime.datetime.now())
archive = FakeArchive("test-archive", datetime.datetime.now())
view = ExtractDialog(test_list, archive)
view.show()
sys.exit(app.exec_())

View File

@ -0,0 +1,273 @@
from PyQt5.QtCore import QAbstractItemModel, QModelIndex, Qt
import os
import abc
from vorta.utils import get_dict_from_list, pretty_bytes
class FolderItem:
def __init__(
self,
path,
name,
modified,
files_with_attributes,
nested_file_list,
selected_files_folders=None,
parent=None,
):
self.parentItem = parent
self.path = path
self.itemData = [name, modified]
self.childItems = []
self.checkedState = False
self.files_with_attributes = files_with_attributes
self.nested_file_list = nested_file_list
self.selected_files_folders = selected_files_folders
# Pre-filter children
self._filtered_children = []
search_path = os.path.join(self.path, name)
if parent is None: # Find path for root folder
for root_folder in nested_file_list.keys():
self._filtered_children.append((0, "", root_folder, "",))
else:
self.checkedState = (
parent.checkedState
) # If there is a parent, use its checked-status.
# This adds direct children.
self._filtered_children = [
f for f in files_with_attributes if search_path == f[3]
]
# Add nested folders.
for immediate_child in get_dict_from_list(
nested_file_list, search_path.split("/")
).keys():
if not [
True
for child in self._filtered_children
if child[2] == immediate_child
]:
self._filtered_children.append(
(0, "", immediate_child, search_path)
)
self.is_loaded = False
def load_children(self):
for child_item in self._filtered_children:
if child_item[0] > 0: # This is a file
self.childItems.append(
FileItem(
name=child_item[2],
modified=child_item[1],
size=child_item[0],
files_with_attributes=self.files_with_attributes,
nested_file_list=self.nested_file_list,
selected_files_folders=self.selected_files_folders,
parent=self,
)
)
else: # Folder
self.childItems.append(
FolderItem(
path=child_item[3],
name=child_item[2],
modified=child_item[1],
files_with_attributes=self.files_with_attributes,
nested_file_list=self.nested_file_list,
selected_files_folders=self.selected_files_folders,
parent=self,
)
)
self.is_loaded = True
def setCheckedState(self, value):
if value == 2:
self.checkedState = True
self.selected_files_folders.add(
os.path.join(
self.parentItem.path, self.parentItem.data(0), self.itemData[0]
)
)
else:
self.checkedState = False
path_to_remove = os.path.join(
self.parentItem.path, self.parentItem.data(0), self.itemData[0]
)
if path_to_remove in self.selected_files_folders:
self.selected_files_folders.remove(path_to_remove)
if hasattr(self, "childItems"):
for child in self.childItems:
child.setCheckedState(value)
def getCheckedState(self):
if self.checkedState:
return Qt.Checked
else:
return Qt.Unchecked
def child(self, row):
return self.childItems[row]
def childCount(self):
return len(self._filtered_children)
def columnCount(self):
return 3
def data(self, column):
if column <= 1:
return self.itemData[column]
else:
return None
def parent(self):
return self.parentItem
def row(self):
if self.parentItem:
return self.parentItem.childItems.index(self)
return 0
class FileItem(FolderItem):
def __init__(
self,
name,
modified,
size,
files_with_attributes,
nested_file_list,
selected_files_folders=None,
parent=None,
):
self.parentItem = parent
self.itemData = [name, modified, size]
self.checkedState = parent.checkedState
self.files_with_attributes = files_with_attributes
self.nested_file_list = nested_file_list
self.selected_files_folders = selected_files_folders
def childCount(self):
return 0
def columnCount(self):
return 3
def data(self, column):
if column == 1:
return self.itemData[column]
elif column == 2:
return pretty_bytes(self.itemData[column])
elif column == 0:
return self.itemData[column]
def parent(self):
return self.parentItem
def row(self):
return self.parentItem.childItems.index(self)
class TreeModel(QAbstractItemModel):
__metaclass__ = abc.ABCMeta
column_names = ["Name", "Modified", "Size"]
def __init__(
self,
files_with_attributes,
nested_file_list,
selected_files_folders=None,
parent=None,
):
super(TreeModel, self).__init__(parent)
self.rootItem = FolderItem(
path="",
name="",
files_with_attributes=files_with_attributes,
nested_file_list=nested_file_list,
selected_files_folders=selected_files_folders,
modified=None,
)
self.rootItem.load_children()
def columnCount(self, parent):
return 3
@abc.abstractmethod
def data(self, index, role):
return
def setData(self, index, value, role=Qt.EditRole):
if role == Qt.CheckStateRole:
item = index.internalPointer()
item.setCheckedState(value)
self.dataChanged.emit(QModelIndex(), QModelIndex(), [])
return True
def canFetchMore(self, index):
if not index.isValid():
return False
item = index.internalPointer()
return not item.is_loaded
def fetchMore(self, index):
item = index.internalPointer()
item.load_children()
@abc.abstractmethod
def flags(self, index):
return
def headerData(self, section, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.column_names[section]
return None
def index(self, row, column, parent):
if not self.hasIndex(row, column, parent):
return QModelIndex()
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
childItem = parentItem.child(row)
if childItem:
return self.createIndex(row, column, childItem)
else:
return QModelIndex()
def parent(self, index):
if not index.isValid():
return QModelIndex()
childItem = index.internalPointer()
parentItem = childItem.parent()
if parentItem == self.rootItem:
return QModelIndex()
return self.createIndex(parentItem.row(), 0, parentItem)
def rowCount(self, parent):
if parent.column() > 0:
return 0
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
return parentItem.childCount()

View File

@ -0,0 +1,2 @@
+7 B 0 B [-rw-rw-r-- -> -rw-rw-rw-] test/hallo
added 0 B test/tschüss

View File

@ -32,6 +32,9 @@ def init_db(qapp):
test_archive = ArchiveModel(snapshot_id='99999', name='test-archive', time=dt(2000, 1, 1, 0, 0), repo=1)
test_archive.save()
test_archive1 = ArchiveModel(snapshot_id='99998', name='test-archive1', time=dt(2000, 1, 1, 0, 0), repo=1)
test_archive1.save()
source_dir = SourceFileModel(dir='/tmp/another', repo=new_repo)
source_dir.save()

View File

@ -115,7 +115,7 @@ def test_archive_extract(qapp, qtbot, mocker, borg_json_output, monkeypatch):
main.tabWidget.setCurrentIndex(3)
tab.populate_from_profile()
qtbot.waitUntil(lambda: tab.archiveTable.rowCount() == 1)
qtbot.waitUntil(lambda: tab.archiveTable.rowCount() == 2)
monkeypatch.setattr(
vorta.views.extract_dialog.ExtractDialog, "exec_", lambda *args: True
@ -131,6 +131,40 @@ def test_archive_extract(qapp, qtbot, mocker, borg_json_output, monkeypatch):
assert tab._window.treeView.model().rootItem.childItems[0].data(0) == 'Users'
tab._window.treeView.model().rootItem.childItems[0].load_children()
assert tab._window.archiveNameLabel.text().startswith('test-archive, 2000')
tab._window.accept()
def test_archive_diff(qapp, qtbot, mocker, borg_json_output, monkeypatch):
main = qapp.main_window
tab = main.archiveTab
main.tabWidget.setCurrentIndex(3)
tab.populate_from_profile()
qtbot.waitUntil(lambda: tab.archiveTable.rowCount() == 2)
monkeypatch.setattr(
vorta.views.diff_dialog.DiffDialog, "exec_", lambda *args: True
)
monkeypatch.setattr(
tab, "selected_archives", (0, 1)
)
stdout, stderr = borg_json_output('diff_archives')
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
mocker.patch.object(vorta.borg.borg_thread, 'Popen', return_value=popen_result)
qtbot.mouseClick(tab.diffButton, QtCore.Qt.LeftButton)
qtbot.waitUntil(lambda: hasattr(tab, '_window'), timeout=5000)
monkeypatch.setattr(
vorta.views.diff_result.DiffResult, "exec_", lambda *args: True
)
qtbot.waitUntil(lambda: hasattr(tab, '_resultwindow'), timeout=5000)
assert tab._resultwindow.treeView.model().rootItem.childItems[0].data(0) == 'test'
tab._resultwindow.treeView.model().rootItem.childItems[0].load_children()
assert tab._resultwindow.archiveNameLabel_1.text() == 'test-archive'
tab._resultwindow.accept()

View File

@ -101,8 +101,8 @@ def test_create(qapp, borg_json_output, mocker, qtbot):
qtbot.waitUntil(lambda: main.createProgressText.text().startswith('Backup finished.'), timeout=3000)
qtbot.waitUntil(lambda: main.createStartBtn.isEnabled(), timeout=3000)
assert EventLogModel.select().count() == 1
assert ArchiveModel.select().count() == 2
assert ArchiveModel.select().count() == 3
assert RepoModel.get(id=1).unique_size == 15520474
assert main.createStartBtn.isEnabled()
assert main.archiveTab.archiveTable.rowCount() == 2
assert main.archiveTab.archiveTable.rowCount() == 3
assert main.scheduleTab.logTableWidget.rowCount() == 1