From 52bfd652dfdfc316005199c6d9f0a38905d63c91 Mon Sep 17 00:00:00 2001 From: Syed Ahmer Shah Date: Sat, 10 Oct 2026 23:50:51 +0500 Subject: [PATCH] Use exclude-if-present entries saved before v0.10.0 --- src/vorta/borg/create.py | 13 ++--------- src/vorta/store/models.py | 19 +++++++++++++++ src/vorta/views/dialogs/archive/exclude.py | 6 ++--- tests/unit/test_create.py | 27 ++++++++++++++++++++++ 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/src/vorta/borg/create.py b/src/vorta/borg/create.py index a00efe9c8..1ab75bd44 100644 --- a/src/vorta/borg/create.py +++ b/src/vorta/borg/create.py @@ -167,17 +167,8 @@ def prepare(cls, profile): ] cmd += extra_cmd_options - # Function to extend command with exclude-if-present patterns - if profile.exclude_if_present is not None: - patterns = [] - for f in profile.exclude_if_present.split('\n'): - f = f.strip() - if f.startswith('[x]'): - patterns.append(f[3:].strip()) # Remove the '[x]' prefix - - for pattern in patterns: - if pattern.strip(): - cmd.extend(['--exclude-if-present', pattern]) + for f in profile.get_exclude_if_present_files(): + cmd.extend(['--exclude-if-present', f]) # Add excludes # Partly inspired by borgmatic/borgmatic/borg/create.py diff --git a/src/vorta/store/models.py b/src/vorta/store/models.py index 9267655fa..83fc74592 100644 --- a/src/vorta/store/models.py +++ b/src/vorta/store/models.py @@ -167,6 +167,25 @@ def get_combined_exclusion_string(self) -> str: return excludes + def get_exclude_if_present_files(self) -> list[str]: + """ + Return the enabled 'exclude if present' file names. + + Each line is stored as '[x] name' (enabled) or '[] name' (disabled). Profiles saved + before v0.10.0 have plain names without a prefix. Those were all active back then, + so they count as enabled, the same as in the exclude dialog. + """ + files = [] + for line in str(self.exclude_if_present or '').split('\n'): + line = line.strip() + if line.startswith('[]'): + continue + if line.startswith('[x]'): + line = line[3:].strip() + if line: + files.append(line) + return files + class Meta: database = DB diff --git a/src/vorta/views/dialogs/archive/exclude.py b/src/vorta/views/dialogs/archive/exclude.py index 48fc1f05f..85c030a32 100644 --- a/src/vorta/views/dialogs/archive/exclude.py +++ b/src/vorta/views/dialogs/archive/exclude.py @@ -241,10 +241,8 @@ def populate_preview_tab(self): preview = self.profile.get_combined_exclusion_string() if self.profile.exclude_if_present: preview += '\n# Exclude if present' - for f in self.profile.exclude_if_present.split('\n'): - f = f.strip() - if f.startswith('[x]'): - preview += '\n' + f[3:].strip() + for f in self.profile.get_exclude_if_present_files(): + preview += '\n' + f self.exclusionsPreviewText.setPlainText(preview) def copy_preview_to_clipboard(self): diff --git a/tests/unit/test_create.py b/tests/unit/test_create.py index c5ada7b38..57225fe55 100644 --- a/tests/unit/test_create.py +++ b/tests/unit/test_create.py @@ -77,3 +77,30 @@ def test_prepare_returns_info_level_when_metered_connection(mocker): mocker.patch('vorta.borg.create.get_network_status_monitor', return_value=mock_monitor) result = BorgCreateJob.prepare(default_profile) assert result.get('level') == 'info' + + +def test_create_exclude_if_present(): + """Plain names saved before v0.10.0 have no [x]/[] prefix and must still be used (#2369).""" + default_profile = BackupProfileModel.get() + default_profile.exclude_if_present = '.NO_BACKUP\n[x] .nobackup\n[] CACHEDIR.TAG\n' + + result = BorgCreateJob.prepare(default_profile) + + cmd = result['cmd'] + assert cmd.count('--exclude-if-present') == 2 + assert cmd[cmd.index('.NO_BACKUP') - 1] == '--exclude-if-present' + assert cmd[cmd.index('.nobackup') - 1] == '--exclude-if-present' + assert 'CACHEDIR.TAG' not in cmd + + +def test_get_exclude_if_present_files(): + profile = BackupProfileModel.get() + + profile.exclude_if_present = None + assert profile.get_exclude_if_present_files() == [] + + profile.exclude_if_present = '[] .nobackup\n[] CACHEDIR.TAG' + assert profile.get_exclude_if_present_files() == [] + + profile.exclude_if_present = '[x] .nobackup\n.NO_BACKUP\n\n[] CACHEDIR.TAG\n[x]' + assert profile.get_exclude_if_present_files() == ['.nobackup', '.NO_BACKUP']