mirror of
https://github.com/borgbase/vorta
synced 2024-12-22 07:43:09 +00:00
Specify archive using -a
for borg v2 mount
.
* src/vorta/views/archive_tab.py : Move all command building logic into `mount.py`. * src/vorta/borg/mount.py (BorgMountJob.prepare): Add command building logic previously in other places. * src/vorta/borg/mount.py (BorgMountJob.prepare): Use `-a` command line option to select a single archive. * src/vorta/utils.py (SHELL_PATTERN_ELEMENT): A pattern that can be used to detect shell pattern syntax. * src/vorta/utils.py (get_mount_points): Implement parsing a borg v2 cmd.
This commit is contained in:
parent
b4a7c5494e
commit
5e046386d7
3 changed files with 58 additions and 28 deletions
|
@ -1,15 +1,18 @@
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
from vorta.store.models import SettingsModel
|
from vorta.store.models import SettingsModel
|
||||||
from vorta.utils import borg_compat
|
from vorta.utils import SHELL_PATTERN_ELEMENT, borg_compat
|
||||||
from .borg_job import BorgJob
|
from .borg_job import BorgJob
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class BorgMountJob(BorgJob):
|
class BorgMountJob(BorgJob):
|
||||||
def started_event(self):
|
def started_event(self):
|
||||||
self.updated.emit(self.tr('Mounting archive into folder…'))
|
self.updated.emit(self.tr('Mounting archive into folder…'))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def prepare(cls, profile):
|
def prepare(cls, profile, archive: str = None):
|
||||||
ret = super().prepare(profile)
|
ret = super().prepare(profile)
|
||||||
if not ret['ok']:
|
if not ret['ok']:
|
||||||
return ret
|
return ret
|
||||||
|
@ -26,8 +29,21 @@ def prepare(cls, profile):
|
||||||
|
|
||||||
if borg_compat.check('V2'):
|
if borg_compat.check('V2'):
|
||||||
cmd.extend(["-r", profile.repo.url])
|
cmd.extend(["-r", profile.repo.url])
|
||||||
|
|
||||||
|
if archive:
|
||||||
|
# in shell patterns ?, * and [...] have a special meaning
|
||||||
|
pattern = SHELL_PATTERN_ELEMENT.sub(r'\\1', archive) # escape them
|
||||||
|
cmd.extend(['-a', pattern])
|
||||||
else:
|
else:
|
||||||
cmd.append(f'{profile.repo.url}')
|
source = f'{profile.repo.url}'
|
||||||
|
|
||||||
|
if archive:
|
||||||
|
source += f'::{archive}'
|
||||||
|
|
||||||
|
cmd.append(source)
|
||||||
|
|
||||||
|
if archive:
|
||||||
|
ret['mounted_archive'] = archive
|
||||||
|
|
||||||
ret['ok'] = True
|
ret['ok'] = True
|
||||||
ret['cmd'] = cmd
|
ret['cmd'] = cmd
|
||||||
|
|
|
@ -358,6 +358,9 @@ def format_archive_name(profile, archive_name_tpl):
|
||||||
return archive_name_tpl.format(**available_vars)
|
return archive_name_tpl.format(**available_vars)
|
||||||
|
|
||||||
|
|
||||||
|
SHELL_PATTERN_ELEMENT = re.compile(r'([?\[\]*])')
|
||||||
|
|
||||||
|
|
||||||
def get_mount_points(repo_url):
|
def get_mount_points(repo_url):
|
||||||
mount_points = {}
|
mount_points = {}
|
||||||
repo_mounts = []
|
repo_mounts = []
|
||||||
|
@ -368,23 +371,41 @@ def get_mount_points(repo_url):
|
||||||
if 'mount' not in proc.cmdline():
|
if 'mount' not in proc.cmdline():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for idx, parameter in enumerate(proc.cmdline()):
|
if borg_compat.check('V2'):
|
||||||
if parameter.startswith(repo_url):
|
# command line syntax:
|
||||||
# mount from this repo
|
# `borg mount -r <repo> <mountpoint> <path> (-a <archive_pattern>)`
|
||||||
|
cmd = proc.cmdline()
|
||||||
|
if repo_url in cmd:
|
||||||
|
i = cmd.index(repo_url)
|
||||||
|
if len(cmd) > i + 1:
|
||||||
|
mount_point = cmd[i + 1]
|
||||||
|
|
||||||
# The borg mount command specifies that the mount_point
|
# Archive mount?
|
||||||
# parameter comes after the archive name
|
ao = '-a' in cmd
|
||||||
if len(proc.cmdline()) > idx + 1:
|
if ao or '--glob-archives' in cmd:
|
||||||
mount_point = proc.cmdline()[idx + 1]
|
i = cmd.index('-a' if ao else '--glob-archives')
|
||||||
|
if len(cmd) >= i + 1 and not SHELL_PATTERN_ELEMENT.search(cmd[i + 1]):
|
||||||
# archive or full mount?
|
mount_points[mount_point] = cmd[i + 1]
|
||||||
if parameter[len(repo_url) :].startswith('::'):
|
|
||||||
archive_name = parameter[len(repo_url) + 2 :]
|
|
||||||
mount_points[archive_name] = mount_point
|
|
||||||
break
|
|
||||||
else:
|
else:
|
||||||
# repo mount point
|
|
||||||
repo_mounts.append(mount_point)
|
repo_mounts.append(mount_point)
|
||||||
|
else:
|
||||||
|
for idx, parameter in enumerate(proc.cmdline()):
|
||||||
|
if parameter.startswith(repo_url):
|
||||||
|
# mount from this repo
|
||||||
|
|
||||||
|
# The borg mount command specifies that the mount_point
|
||||||
|
# parameter comes after the archive name
|
||||||
|
if len(proc.cmdline()) > idx + 1:
|
||||||
|
mount_point = proc.cmdline()[idx + 1]
|
||||||
|
|
||||||
|
# archive or full mount?
|
||||||
|
if parameter[len(repo_url) :].startswith('::'):
|
||||||
|
archive_name = parameter[len(repo_url) + 2 :]
|
||||||
|
mount_points[archive_name] = mount_point
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# repo mount point
|
||||||
|
repo_mounts.append(mount_point)
|
||||||
|
|
||||||
except (psutil.ZombieProcess, psutil.AccessDenied, psutil.NoSuchProcess):
|
except (psutil.ZombieProcess, psutil.AccessDenied, psutil.NoSuchProcess):
|
||||||
# Getting process details may fail (e.g. zombie process on macOS)
|
# Getting process details may fail (e.g. zombie process on macOS)
|
||||||
|
|
|
@ -52,7 +52,7 @@ def __init__(self, parent=None, app=None):
|
||||||
"""Init."""
|
"""Init."""
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setupUi(parent)
|
self.setupUi(parent)
|
||||||
self.mount_points = {} # mount points of archives
|
self.mount_points = {} # mapping of archive name to mount point
|
||||||
self.repo_mount_point: Optional[str] = None # mount point of whole repo
|
self.repo_mount_point: Optional[str] = None # mount point of whole repo
|
||||||
self.menu = None
|
self.menu = None
|
||||||
self.app = app
|
self.app = app
|
||||||
|
@ -565,17 +565,11 @@ def mount_action(self, archive_name=None):
|
||||||
The archive to mount or None, by default None
|
The archive to mount or None, by default None
|
||||||
"""
|
"""
|
||||||
profile = self.profile()
|
profile = self.profile()
|
||||||
params = BorgMountJob.prepare(profile)
|
params = BorgMountJob.prepare(profile, archive=archive_name)
|
||||||
if not params['ok']:
|
if not params['ok']:
|
||||||
self._set_status(params['message'])
|
self._set_status(params['message'])
|
||||||
return
|
return
|
||||||
|
|
||||||
if archive_name:
|
|
||||||
# mount archive
|
|
||||||
params['cmd'][-1] += f'::{archive_name}'
|
|
||||||
params['current_archive'] = archive_name
|
|
||||||
# else mount complete repo
|
|
||||||
|
|
||||||
def receive():
|
def receive():
|
||||||
mount_point = dialog.selectedFiles()
|
mount_point = dialog.selectedFiles()
|
||||||
if mount_point:
|
if mount_point:
|
||||||
|
@ -598,13 +592,12 @@ def mount_result(self, result):
|
||||||
|
|
||||||
mount_point = result['params']['mount_point']
|
mount_point = result['params']['mount_point']
|
||||||
|
|
||||||
if result['params'].get('current_archive'):
|
if result['params'].get('mounted_archive'):
|
||||||
# archive was mounted
|
# archive was mounted
|
||||||
archive_name = result['params']['current_archive']
|
archive_name = result['params']['mounted_archive']
|
||||||
self.mount_points[archive_name] = mount_point
|
self.mount_points[archive_name] = mount_point
|
||||||
|
|
||||||
# update column in table
|
# update column in table
|
||||||
archive_name = result['params']['current_archive']
|
|
||||||
row = self.row_of_archive(archive_name)
|
row = self.row_of_archive(archive_name)
|
||||||
item = QTableWidgetItem(result['cmd'][-1])
|
item = QTableWidgetItem(result['cmd'][-1])
|
||||||
self.archiveTable.setItem(row, 3, item)
|
self.archiveTable.setItem(row, 3, item)
|
||||||
|
|
Loading…
Reference in a new issue