Selaa lähdekoodia

Fix for borgmatic "exclude_patterns" and "exclude_from" recursing into excluded subdirectories (#982).

Dan Helfman 4 kuukautta sitten
vanhempi
sitoutus
b6ff242d3a

+ 4 - 0
NEWS

@@ -1,3 +1,7 @@
+1.9.9.dev0
+ * #982: Fix for borgmatic "exclude_patterns" and "exclude_from" recursing into excluded
+   subdirectories.
+
 1.9.8
  * #979: Fix root patterns so they don't have an invalid "sh:" prefix before getting passed to Borg.
  * Expand the recent contributors documentation section to include ticket submitters—not just code

+ 2 - 2
borgmatic/actions/create.py

@@ -62,7 +62,7 @@ def collect_patterns(config):
             )
             + tuple(
                 parse_pattern(
-                    f'{borgmatic.borg.pattern.Pattern_type.EXCLUDE.value} {exclude_line.strip()}',
+                    f'{borgmatic.borg.pattern.Pattern_type.NO_RECURSE.value} {exclude_line.strip()}',
                     borgmatic.borg.pattern.Pattern_style.FNMATCH,
                 )
                 for exclude_line in config.get('exclude_patterns', ())
@@ -76,7 +76,7 @@ def collect_patterns(config):
             )
             + tuple(
                 parse_pattern(
-                    f'{borgmatic.borg.pattern.Pattern_type.EXCLUDE.value} {exclude_line.strip()}',
+                    f'{borgmatic.borg.pattern.Pattern_type.NO_RECURSE.value} {exclude_line.strip()}',
                     borgmatic.borg.pattern.Pattern_style.FNMATCH,
                 )
                 for filename in config.get('exclude_from', ())

+ 6 - 2
borgmatic/borg/create.py

@@ -36,14 +36,18 @@ def write_patterns_file(patterns, borgmatic_runtime_directory, log_prefix, patte
 
     if patterns_file is None:
         patterns_file = tempfile.NamedTemporaryFile('w', dir=borgmatic_runtime_directory)
+        operation_name = 'Writing'
     else:
         patterns_file.write('\n')
+        operation_name = 'Appending'
 
     patterns_output = '\n'.join(
         f'{pattern.type.value} {pattern.style.value}{":" if pattern.style.value else ""}{pattern.path}'
         for pattern in patterns
     )
-    logger.debug(f'{log_prefix}: Writing patterns to {patterns_file.name}:\n{patterns_output}')
+    logger.debug(
+        f'{log_prefix}: {operation_name} patterns to {patterns_file.name}:\n{patterns_output}'
+    )
 
     patterns_file.write(patterns_output)
     patterns_file.flush()
@@ -328,7 +332,7 @@ def make_base_create_command(
                 tuple(
                     borgmatic.borg.pattern.Pattern(
                         special_file_path,
-                        borgmatic.borg.pattern.Pattern_type.EXCLUDE,
+                        borgmatic.borg.pattern.Pattern_type.NO_RECURSE,
                         borgmatic.borg.pattern.Pattern_style.FNMATCH,
                     )
                     for special_file_path in special_file_paths

+ 1 - 1
borgmatic/hooks/data_source/btrfs.py

@@ -151,7 +151,7 @@ def make_snapshot_exclude_pattern(subvolume_path):  # pragma: no cover
             subvolume_path.lstrip(os.path.sep),
             snapshot_directory,
         ),
-        borgmatic.borg.pattern.Pattern_type.EXCLUDE,
+        borgmatic.borg.pattern.Pattern_type.NO_RECURSE,
         borgmatic.borg.pattern.Pattern_style.FNMATCH,
     )
 

+ 1 - 1
pyproject.toml

@@ -1,6 +1,6 @@
 [project]
 name = "borgmatic"
-version = "1.9.8"
+version = "1.9.9.dev0"
 authors = [
   { name="Dan Helfman", email="witten@torsion.org" },
 ]

+ 12 - 12
tests/unit/actions/test_create.py

@@ -48,9 +48,9 @@ def test_collect_patterns_parses_config_patterns():
 
 def test_collect_patterns_converts_exclude_patterns():
     assert module.collect_patterns({'exclude_patterns': ['/foo', '/bar', 'sh:**/baz']}) == (
-        Pattern('/foo', Pattern_type.EXCLUDE, Pattern_style.FNMATCH),
-        Pattern('/bar', Pattern_type.EXCLUDE, Pattern_style.FNMATCH),
-        Pattern('**/baz', Pattern_type.EXCLUDE, Pattern_style.SHELL),
+        Pattern('/foo', Pattern_type.NO_RECURSE, Pattern_style.FNMATCH),
+        Pattern('/bar', Pattern_type.NO_RECURSE, Pattern_style.FNMATCH),
+        Pattern('**/baz', Pattern_type.NO_RECURSE, Pattern_style.SHELL),
     )
 
 
@@ -90,22 +90,22 @@ def test_collect_patterns_reads_config_exclude_from_file():
         io.StringIO('/bar\n# comment\n\n   \n/baz')
     )
     flexmock(module).should_receive('parse_pattern').with_args(
-        '- /foo', default_style=Pattern_style.FNMATCH
-    ).and_return(Pattern('/foo', Pattern_type.EXCLUDE, Pattern_style.FNMATCH))
+        '! /foo', default_style=Pattern_style.FNMATCH
+    ).and_return(Pattern('/foo', Pattern_type.NO_RECURSE, Pattern_style.FNMATCH))
     flexmock(module).should_receive('parse_pattern').with_args(
-        '- /bar', default_style=Pattern_style.FNMATCH
-    ).and_return(Pattern('/bar', Pattern_type.EXCLUDE, Pattern_style.FNMATCH))
+        '! /bar', default_style=Pattern_style.FNMATCH
+    ).and_return(Pattern('/bar', Pattern_type.NO_RECURSE, Pattern_style.FNMATCH))
     flexmock(module).should_receive('parse_pattern').with_args('# comment').never()
     flexmock(module).should_receive('parse_pattern').with_args('').never()
     flexmock(module).should_receive('parse_pattern').with_args('   ').never()
     flexmock(module).should_receive('parse_pattern').with_args(
-        '- /baz', default_style=Pattern_style.FNMATCH
-    ).and_return(Pattern('/baz', Pattern_type.EXCLUDE, Pattern_style.FNMATCH))
+        '! /baz', default_style=Pattern_style.FNMATCH
+    ).and_return(Pattern('/baz', Pattern_type.NO_RECURSE, Pattern_style.FNMATCH))
 
     assert module.collect_patterns({'exclude_from': ['file1.txt', 'file2.txt']}) == (
-        Pattern('/foo', Pattern_type.EXCLUDE, Pattern_style.FNMATCH),
-        Pattern('/bar', Pattern_type.EXCLUDE, Pattern_style.FNMATCH),
-        Pattern('/baz', Pattern_type.EXCLUDE, Pattern_style.FNMATCH),
+        Pattern('/foo', Pattern_type.NO_RECURSE, Pattern_style.FNMATCH),
+        Pattern('/bar', Pattern_type.NO_RECURSE, Pattern_style.FNMATCH),
+        Pattern('/baz', Pattern_type.NO_RECURSE, Pattern_style.FNMATCH),
     )
 
 

+ 2 - 2
tests/unit/borg/test_create.py

@@ -665,7 +665,7 @@ def test_make_base_create_command_with_stream_processes_ignores_read_special_fal
         (
             Pattern(
                 '/dev/null',
-                Pattern_type.EXCLUDE,
+                Pattern_type.NO_RECURSE,
                 Pattern_style.FNMATCH,
             ),
         ),
@@ -716,7 +716,7 @@ def test_make_base_create_command_without_patterns_and_with_stream_processes_ign
         (
             Pattern(
                 '/dev/null',
-                Pattern_type.EXCLUDE,
+                Pattern_type.NO_RECURSE,
                 Pattern_style.FNMATCH,
             ),
         ),

+ 12 - 12
tests/unit/hooks/data_source/test_btrfs.py

@@ -218,7 +218,7 @@ def test_dump_data_sources_snapshots_each_subvolume_and_updates_patterns():
     ).and_return(
         Pattern(
             '/mnt/subvol1/.borgmatic-1234/mnt/subvol1/.borgmatic-1234',
-            Pattern_type.EXCLUDE,
+            Pattern_type.NO_RECURSE,
             Pattern_style.FNMATCH,
         )
     )
@@ -227,7 +227,7 @@ def test_dump_data_sources_snapshots_each_subvolume_and_updates_patterns():
     ).and_return(
         Pattern(
             '/mnt/subvol2/.borgmatic-1234/mnt/subvol2/.borgmatic-1234',
-            Pattern_type.EXCLUDE,
+            Pattern_type.NO_RECURSE,
             Pattern_style.FNMATCH,
         )
     )
@@ -256,13 +256,13 @@ def test_dump_data_sources_snapshots_each_subvolume_and_updates_patterns():
         Pattern('/mnt/subvol1/.borgmatic-1234/mnt/subvol1'),
         Pattern(
             '/mnt/subvol1/.borgmatic-1234/mnt/subvol1/.borgmatic-1234',
-            Pattern_type.EXCLUDE,
+            Pattern_type.NO_RECURSE,
             Pattern_style.FNMATCH,
         ),
         Pattern('/mnt/subvol2/.borgmatic-1234/mnt/subvol2'),
         Pattern(
             '/mnt/subvol2/.borgmatic-1234/mnt/subvol2/.borgmatic-1234',
-            Pattern_type.EXCLUDE,
+            Pattern_type.NO_RECURSE,
             Pattern_style.FNMATCH,
         ),
     ]
@@ -288,7 +288,7 @@ def test_dump_data_sources_uses_custom_btrfs_command_in_commands():
     ).and_return(
         Pattern(
             '/mnt/subvol1/.borgmatic-1234/mnt/subvol1/.borgmatic-1234',
-            Pattern_type.EXCLUDE,
+            Pattern_type.NO_RECURSE,
             Pattern_style.FNMATCH,
         )
     )
@@ -314,7 +314,7 @@ def test_dump_data_sources_uses_custom_btrfs_command_in_commands():
         Pattern('/mnt/subvol1/.borgmatic-1234/mnt/subvol1'),
         Pattern(
             '/mnt/subvol1/.borgmatic-1234/mnt/subvol1/.borgmatic-1234',
-            Pattern_type.EXCLUDE,
+            Pattern_type.NO_RECURSE,
             Pattern_style.FNMATCH,
         ),
     ]
@@ -344,7 +344,7 @@ def test_dump_data_sources_uses_custom_findmnt_command_in_commands():
     ).and_return(
         Pattern(
             '/mnt/subvol1/.borgmatic-1234/mnt/subvol1/.borgmatic-1234',
-            Pattern_type.EXCLUDE,
+            Pattern_type.NO_RECURSE,
             Pattern_style.FNMATCH,
         )
     )
@@ -370,7 +370,7 @@ def test_dump_data_sources_uses_custom_findmnt_command_in_commands():
         Pattern('/mnt/subvol1/.borgmatic-1234/mnt/subvol1'),
         Pattern(
             '/mnt/subvol1/.borgmatic-1234/mnt/subvol1/.borgmatic-1234',
-            Pattern_type.EXCLUDE,
+            Pattern_type.NO_RECURSE,
             Pattern_style.FNMATCH,
         ),
     ]
@@ -461,7 +461,7 @@ def test_dump_data_sources_snapshots_adds_to_existing_exclude_patterns():
     ).and_return(
         Pattern(
             '/mnt/subvol1/.borgmatic-1234/mnt/subvol1/.borgmatic-1234',
-            Pattern_type.EXCLUDE,
+            Pattern_type.NO_RECURSE,
             Pattern_style.FNMATCH,
         )
     )
@@ -470,7 +470,7 @@ def test_dump_data_sources_snapshots_adds_to_existing_exclude_patterns():
     ).and_return(
         Pattern(
             '/mnt/subvol2/.borgmatic-1234/mnt/subvol2/.borgmatic-1234',
-            Pattern_type.EXCLUDE,
+            Pattern_type.NO_RECURSE,
             Pattern_style.FNMATCH,
         )
     )
@@ -499,13 +499,13 @@ def test_dump_data_sources_snapshots_adds_to_existing_exclude_patterns():
         Pattern('/mnt/subvol1/.borgmatic-1234/mnt/subvol1'),
         Pattern(
             '/mnt/subvol1/.borgmatic-1234/mnt/subvol1/.borgmatic-1234',
-            Pattern_type.EXCLUDE,
+            Pattern_type.NO_RECURSE,
             Pattern_style.FNMATCH,
         ),
         Pattern('/mnt/subvol2/.borgmatic-1234/mnt/subvol2'),
         Pattern(
             '/mnt/subvol2/.borgmatic-1234/mnt/subvol2/.borgmatic-1234',
-            Pattern_type.EXCLUDE,
+            Pattern_type.NO_RECURSE,
             Pattern_style.FNMATCH,
         ),
     ]