-
Notifications
You must be signed in to change notification settings - Fork 134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: quick mount #1664
base: master
Are you sure you want to change the base?
feat: quick mount #1664
Changes from 4 commits
3e82c5f
24f418e
eaf03b2
fdf9c69
317cd0b
ac624ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
import logging | ||
import os | ||
import random | ||
import shutil | ||
import string | ||
import sys | ||
from datetime import timedelta | ||
from typing import Dict, Optional | ||
from PyQt5 import QtCore, uic | ||
from PyQt5.QtCore import QItemSelectionModel, QMimeData, QPoint, Qt, pyqtSlot | ||
from PyQt5.QtCore import QItemSelectionModel, QMimeData, QPoint, Qt, QUrl, pyqtSlot | ||
from PyQt5.QtGui import QDesktopServices, QKeySequence | ||
from PyQt5.QtWidgets import ( | ||
QAction, | ||
|
@@ -106,7 +110,6 @@ def __init__(self, parent=None, app=None): | |
self.archiveTable.selectionModel().selectionChanged.connect(self.on_selection_change) | ||
|
||
# connect archive actions | ||
self.bMountArchive.clicked.connect(self.bmountarchive_clicked) | ||
self.bRefreshArchive.clicked.connect(self.refresh_archive_info) | ||
self.bRename.clicked.connect(self.rename_action) | ||
self.bDelete.clicked.connect(self.delete_action) | ||
|
@@ -118,7 +121,17 @@ def __init__(self, parent=None, app=None): | |
self.bPrune.clicked.connect(self.prune_action) | ||
self.bCheck.clicked.connect(self.check_action) | ||
self.bDiff.clicked.connect(self.diff_action) | ||
self.bMountRepo.clicked.connect(self.bmountrepo_clicked) | ||
self.menuMountArchive = QMenu(self.bMountArchive) | ||
self.menuMountArchive.addAction(translate("MountArchive", "Mount to Folder…"), self.bmountarchive_clicked) | ||
self.menuMountArchive.addAction( | ||
translate("MountArchive", "Quick Mount…"), lambda: self.bmountarchive_clicked(True) | ||
) | ||
self.bMountArchive.setMenu(self.menuMountArchive) | ||
|
||
self.menuMountRepo = QMenu(self.bMountRepo) | ||
self.menuMountRepo.addAction(translate("MountRepo", "Mount to Folder…"), self.bmountrepo_clicked) | ||
self.menuMountRepo.addAction(translate("MountRepo", "Quick Mount…"), self.quick_mount_action) | ||
self.bMountRepo.setMenu(self.menuMountRepo) | ||
|
||
self.archiveNameTemplate.textChanged.connect( | ||
lambda tpl, key='new_archive_name': self.save_archive_template(tpl, key) | ||
|
@@ -366,6 +379,7 @@ def on_selection_change(self, selected=None, deselected=None): | |
|
||
# special treatment for dynamic mount/unmount button. | ||
self.bmountarchive_refresh() | ||
self.bmountrepo_refresh() | ||
tooltip = self.bMountArchive.toolTip() | ||
self.bMountArchive.setToolTip(tooltip + " " + self.tr("(Select exactly one archive)")) | ||
|
||
|
@@ -502,7 +516,7 @@ def selected_archive_name(self): | |
return archive_cell.text() | ||
return None | ||
|
||
def bmountarchive_clicked(self): | ||
def bmountarchive_clicked(self, quick=False): | ||
""" | ||
Handle `bMountArchive` being clicked. | ||
|
||
|
@@ -516,9 +530,46 @@ def bmountarchive_clicked(self): | |
|
||
if archive_name in self.mount_points: | ||
self.unmount_action(archive_name=archive_name) | ||
elif quick: | ||
self.quick_mount_action(archive_name=archive_name) | ||
else: | ||
self.mount_action(archive_name=archive_name) | ||
|
||
def get_vorta_quick_mountpoint(self): | ||
""" | ||
return a temporary directory in the user's home folder ~/vorta-quick-mount-{randomcharacters} | ||
""" | ||
return os.path.join( | ||
os.path.expanduser('~'), | ||
'vorta-quick-mount-' + ''.join(random.choices(string.ascii_lowercase + string.digits, k=6)), | ||
) | ||
|
||
def quick_mount_action(self, archive_name=None): | ||
""" | ||
mount the selected archive or repository to a temporary directory. | ||
""" | ||
profile = self.profile() | ||
params = BorgMountJob.prepare(profile, archive=archive_name) | ||
if not params['ok']: | ||
self._set_status(params['message']) | ||
return | ||
|
||
mount_point = self.get_vorta_quick_mountpoint() | ||
while os.path.exists(mount_point) and os.listdir(mount_point): | ||
mount_point = self.get_vorta_quick_mountpoint() | ||
|
||
os.mkdir(mount_point) | ||
|
||
params['cmd'].append(mount_point) | ||
params['mount_point'] = mount_point | ||
|
||
if params['ok']: | ||
self._toggle_all_buttons(False) | ||
job = BorgMountJob(params['cmd'], params, self.profile().repo.id) | ||
job.updated.connect(self.mountErrors.setText) | ||
job.result.connect(lambda result: self.mount_result(result, quick=True)) | ||
self.app.jobs_manager.add_job(job) | ||
|
||
def bmountrepo_clicked(self): | ||
""" | ||
Handle `bMountRepo` being clicked. | ||
|
@@ -544,11 +595,22 @@ def bmountarchive_refresh(self, icon_only=False): | |
if not icon_only: | ||
self.bMountArchive.setText(self.tr("Unmount")) | ||
self.bMountArchive.setToolTip(self.tr('Unmount the selected archive from the file system')) | ||
self.bMountArchive.setMenu(None) | ||
try: | ||
self.bMountArchive.clicked.disconnect(self.bmountarchive_clicked) # avoid race condition | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would |
||
self.bMountArchive.clicked.connect(self.bmountarchive_clicked) | ||
except TypeError: | ||
self.bMountArchive.clicked.connect(self.bmountarchive_clicked) | ||
Comment on lines
+645
to
+647
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are there two calls to |
||
else: | ||
self.bMountArchive.setIcon(get_colored_icon('folder-open')) | ||
if not icon_only: | ||
self.bMountArchive.setText(self.tr("Mount…")) | ||
self.bMountArchive.setToolTip(self.tr("Mount the selected archive " + "as a folder in the file system")) | ||
try: | ||
self.bMountArchive.clicked.disconnect(self.bmountarchive_clicked) | ||
self.bMountArchive.setMenu(self.menuMountArchive) | ||
except TypeError: # when bMountArchive.clicked is not connected | ||
pass | ||
|
||
def bmountrepo_refresh(self): | ||
""" | ||
|
@@ -561,10 +623,18 @@ def bmountrepo_refresh(self): | |
self.bMountRepo.setText(self.tr("Unmount")) | ||
self.bMountRepo.setToolTip(self.tr('Unmount the repository from the file system')) | ||
self.bMountRepo.setIcon(get_colored_icon('eject')) | ||
self.bMountRepo.setMenu(None) | ||
self.bMountRepo.clicked.connect(self.bmountrepo_clicked) | ||
else: | ||
try: | ||
# disconnect the button to open the menu | ||
self.bMountRepo.clicked.disconnect(self.bmountrepo_clicked) | ||
except TypeError: # on first run, when the button is not connected | ||
pass | ||
self.bMountRepo.setText(self.tr("Mount…")) | ||
self.bMountRepo.setIcon(get_colored_icon('folder-open')) | ||
self.bMountRepo.setToolTip(self.tr("Mount the repository as a folder in the file system")) | ||
self.bMountRepo.setMenu(self.menuMountRepo) | ||
|
||
def mount_action(self, archive_name=None): | ||
""" | ||
|
@@ -600,12 +670,16 @@ def receive(): | |
dialog = choose_file_dialog(self, self.tr("Choose Mount Point"), want_folder=True) | ||
dialog.open(receive) | ||
|
||
def mount_result(self, result): | ||
def mount_result(self, result, quick=False): | ||
if result['returncode'] == 0: | ||
self._set_status(self.tr('Mounted successfully.')) | ||
|
||
mount_point = result['params']['mount_point'] | ||
|
||
if quick: | ||
# open the folder | ||
QDesktopServices.openUrl(QUrl.fromLocalFile(mount_point)) | ||
|
||
if result['params'].get('mounted_archive'): | ||
# archive was mounted | ||
archive_name = result['params']['mounted_archive'] | ||
|
@@ -662,6 +736,8 @@ def umount_result(self, result): | |
|
||
if result['returncode'] == 0: | ||
self._set_status(self.tr('Un-mounted successfully.')) | ||
if os.path.basename(mount_point).startswith("vorta-quick-mount-"): | ||
shutil.rmtree(mount_point) | ||
|
||
if archive_name: | ||
# unmount single archive | ||
|
@@ -670,7 +746,6 @@ def umount_result(self, result): | |
item = QTableWidgetItem('') | ||
self.archiveTable.setItem(row, 3, item) | ||
|
||
# update button | ||
self.bmountarchive_refresh() | ||
else: | ||
# unmount repo | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is that needed? I guess it doesn't hurt either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To support changing the repository from the dropdown in the
Repository
tab. Without this, the Unmount option is visible for all repositories when I restart Vorta and not just the one I mounted.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would make more sense in
_toggle_all_buttons