Skip to content

Commit

Permalink
Display number of files and sizes in source tab. By @XXXBold (#617)
Browse files Browse the repository at this point in the history
  • Loading branch information
XXXBold authored Oct 30, 2020
1 parent 5df8061 commit 461ea05
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 22 deletions.
73 changes: 67 additions & 6 deletions src/vorta/assets/UI/sourcetab.ui
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0">
<item>
<widget class="QListWidget" name="sourceFilesWidget">
<widget class="QTableWidget" name="sourceFilesWidget">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
Expand All @@ -37,12 +40,50 @@
<height>0</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Path</string>
</property>
</column>
<column>
<property name="text">
<string>Type</string>
</property>
</column>
<column>
<property name="text">
<string>Size</string>
</property>
</column>
<column>
<property name="text">
<string>File Count</string>
</property>
</column>
</widget>
</item>
<item>
Expand All @@ -61,6 +102,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="sourceRemove">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="paste">
<property name="toolTip">
Expand All @@ -71,13 +119,26 @@
</property>
</widget>
</item>
<item alignment="Qt::AlignTop">
<widget class="QPushButton" name="sourceRemove">
<item>
<widget class="QPushButton" name="sourcesUpdate">
<property name="text">
<string>Remove</string>
<string>Recalculate sizes</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
Expand Down
21 changes: 20 additions & 1 deletion src/vorta/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from vorta.i18n import trans_late
from vorta.utils import slugify

SCHEMA_VERSION = 15
SCHEMA_VERSION = 16

db = pw.Proxy()

Expand Down Expand Up @@ -106,6 +106,9 @@ class Meta:
class SourceFileModel(pw.Model):
"""A folder to be backed up, related to a Backup Configuration."""
dir = pw.CharField()
dir_size = pw.BigIntegerField()
dir_files_count = pw.BigIntegerField()
path_isdir = pw.BooleanField()
profile = pw.ForeignKeyField(BackupProfileModel, default=1)
added_at = pw.DateTimeField(default=datetime.utcnow)

Expand Down Expand Up @@ -215,6 +218,11 @@ def get_misc_settings():
'label': trans_late('settings',
'Open main window on startup')
},
{
'key': 'get_srcpath_datasize', 'value': True, 'type': 'checkbox',
'label': trans_late('settings',
'Get statistics of file/folder when added')
},
{
'key': 'previous_profile_id', 'str_value': '1', 'type': 'internal',
'label': 'Previously selected profile'
Expand Down Expand Up @@ -362,6 +370,17 @@ def init_db(con=None):
'dont_run_on_metered_networks', pw.BooleanField(default=True))
)

if current_schema.version < 16:
_apply_schema_update(
current_schema, 16,
migrator.add_column(SourceFileModel._meta.table_name,
'dir_size', pw.BigIntegerField(default=-1)),
migrator.add_column(SourceFileModel._meta.table_name,
'dir_files_count', pw.BigIntegerField(default=-1)),
migrator.add_column(SourceFileModel._meta.table_name,
'path_isdir', pw.BooleanField(default=False))
)

# Create missing settings and update labels. Leave setting values untouched.
for setting in get_misc_settings():
s, created = SettingsModel.get_or_create(key=setting['key'], defaults=setting)
Expand Down
74 changes: 72 additions & 2 deletions src/vorta/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from paramiko.ed25519key import Ed25519Key
from paramiko.rsakey import RSAKey
from PyQt5 import QtCore
from PyQt5.QtCore import QFileInfo, QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication, QFileDialog, QSystemTrayIcon

from vorta.borg._compatibility import BorgCompatibility
Expand All @@ -27,9 +28,48 @@
QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True) # use highdpi icons

borg_compat = BorgCompatibility()
_network_status_monitor = None


_network_status_monitor = None
class FilePathInfoAsync(QThread):
signal = pyqtSignal(str, str, str)

def __init__(self, path):
self.path = path
QThread.__init__(self)
self.exiting = False

def run(self):
# logger.info("running thread to get path=%s...", self.path)
self.files_count = 0
self.size, self.files_count = get_path_datasize(self.path)
self.signal.emit(self.path, str(self.size), str(self.files_count))


def get_directory_size(dir_path):
''' Get number of files only and total size in bytes from a path.
Based off https://stackoverflow.com/a/17936789 '''
data_size = 0
seen = set()

for curr_path, _, file_names in os.walk(dir_path):
for file_name in file_names:
file_path = os.path.join(curr_path, file_name)

# Ignore symbolic links, since borg doesn't follow them
if os.path.islink(file_path):
continue

stat = os.stat(file_path)

# Visit each file once
if stat.st_ino not in seen:
seen.add(stat.st_ino)
data_size += stat.st_size

files_count = len(seen)

return data_size, files_count


def get_network_status_monitor():
Expand All @@ -40,6 +80,22 @@ def get_network_status_monitor():
return _network_status_monitor


def get_path_datasize(path):
file_info = QFileInfo(path)
data_size = 0

if file_info.isDir():
data_size, files_count = get_directory_size(file_info.absoluteFilePath())
# logger.info("path (folder) %s %u elements size now=%u (%s)",
# file_info.absoluteFilePath(), files_count, data_size, pretty_bytes(data_size))
else:
# logger.info("path (file) %s size=%u", file_info.path(), file_info.size())
data_size = file_info.size()
files_count = 1

return data_size, files_count


def nested_dict():
"""
Combination of two idioms to quickly build dicts from lists of keys:
Expand Down Expand Up @@ -98,10 +154,24 @@ def get_private_keys():
return available_private_keys


def sort_sizes(size_list):
""" Sorts sizes with extensions. Assumes that size is already in largest unit possible """
final_list = []
for suffix in [" B", " KB", " MB", " GB", " TB"]:
sub_list = [float(size[:-len(suffix)])
for size in size_list if size.endswith(suffix) and size[:-len(suffix)][-1].isnumeric()]
sub_list.sort()
final_list += [(str(size) + suffix) for size in sub_list]
# Skip additional loops
if len(final_list) == len(size_list):
break
return final_list


def pretty_bytes(size):
"""from https://stackoverflow.com/questions/12523586/
python-format-size-application-converting-b-to-kb-mb-gb-tb/37423778"""
if type(size) != int:
if not isinstance(size, int):
return ''
power = 1000 # GiB is base 2**10, GB is base 10**3.
n = 0
Expand Down
Loading

0 comments on commit 461ea05

Please sign in to comment.