Browse Source

Add flags to borg extract Command (Fixes #8564) (#8575)

borg extract --dry-run now displays +/- flags (included/excluded) left to the path.
Syed Ali Ghazi Ejaz 5 months ago
parent
commit
ec3c7b5770
2 changed files with 59 additions and 23 deletions
  1. 40 23
      src/borg/archiver/extract_cmd.py
  2. 19 0
      src/borg/testsuite/archiver/extract_cmd_test.py

+ 40 - 23
src/borg/archiver/extract_cmd.py

@@ -56,33 +56,50 @@ class ExtractMixIn:
         else:
         else:
             pi = None
             pi = None
 
 
-        for item in archive.iter_items(filter):
-            archive.preload_item_chunks(item, optimize_hardlinks=True)
+        for item in archive.iter_items():
             orig_path = item.path
             orig_path = item.path
             if strip_components:
             if strip_components:
-                item.path = os.sep.join(orig_path.split(os.sep)[strip_components:])
-            if not args.dry_run:
-                while dirs and not item.path.startswith(dirs[-1].path):
-                    dir_item = dirs.pop(-1)
-                    try:
-                        archive.extract_item(dir_item, stdout=stdout)
-                    except BackupError as e:
-                        self.print_warning_instance(BackupWarning(remove_surrogates(dir_item.path), e))
+                stripped_path = os.sep.join(orig_path.split(os.sep)[strip_components:])
+                if not stripped_path:
+                    continue
+                item.path = stripped_path
+
+            is_matched = matcher.match(orig_path)
+
             if output_list:
             if output_list:
-                logging.getLogger("borg.output.list").info(remove_surrogates(item.path))
-            try:
-                if dry_run:
-                    archive.extract_item(item, dry_run=True, hlm=hlm, pi=pi)
-                else:
-                    if stat.S_ISDIR(item.mode):
-                        dirs.append(item)
-                        archive.extract_item(item, stdout=stdout, restore_attrs=False)
+                log_prefix = "+" if is_matched else "-"
+                logging.getLogger("borg.output.list").info(f"{log_prefix} {remove_surrogates(item.path)}")
+
+            if is_matched:
+                archive.preload_item_chunks(item, optimize_hardlinks=True)
+
+                if not dry_run:
+                    while dirs and not item.path.startswith(dirs[-1].path):
+                        dir_item = dirs.pop(-1)
+                        try:
+                            archive.extract_item(dir_item, stdout=stdout)
+                        except BackupError as e:
+                            self.print_warning_instance(BackupWarning(remove_surrogates(dir_item.path), e))
+
+                try:
+                    if dry_run:
+                        archive.extract_item(item, dry_run=True, hlm=hlm, pi=pi)
                     else:
                     else:
-                        archive.extract_item(
-                            item, stdout=stdout, sparse=sparse, hlm=hlm, pi=pi, continue_extraction=continue_extraction
-                        )
-            except BackupError as e:
-                self.print_warning_instance(BackupWarning(remove_surrogates(orig_path), e))
+                        if stat.S_ISDIR(item.mode):
+                            dirs.append(item)
+                            archive.extract_item(item, stdout=stdout, restore_attrs=False)
+                        else:
+                            archive.extract_item(
+                                item,
+                                stdout=stdout,
+                                sparse=sparse,
+                                hlm=hlm,
+                                pi=pi,
+                                continue_extraction=continue_extraction,
+                            )
+                except BackupError as e:
+                    self.print_warning_instance(BackupWarning(remove_surrogates(orig_path), e))
+
         if pi:
         if pi:
             pi.finish()
             pi.finish()
 
 

+ 19 - 0
src/borg/testsuite/archiver/extract_cmd_test.py

@@ -718,3 +718,22 @@ def test_extract_continue(archivers, request):
             assert f.read() == CONTENTS2
             assert f.read() == CONTENTS2
         with open("input/file3", "rb") as f:
         with open("input/file3", "rb") as f:
             assert f.read() == CONTENTS3
             assert f.read() == CONTENTS3
+
+
+def test_dry_run_extraction_flags(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    cmd(archiver, "repo-create", RK_ENCRYPTION)
+    create_regular_file(archiver.input_path, "file1", 0)
+    create_regular_file(archiver.input_path, "file2", 0)
+    create_regular_file(archiver.input_path, "file3", 0)
+    cmd(archiver, "create", "test", "input")
+
+    output = cmd(archiver, "extract", "--dry-run", "--list", "test", "-e", "input/file3")
+
+    expected_output = ["+ input/file1", "+ input/file2", "- input/file3"]
+    output_lines = output.splitlines()
+    for expected in expected_output:
+        assert expected in output_lines, f"Expected line not found: {expected}"
+        print(output)
+
+    assert not os.listdir("output"), "Output directory should be empty after dry-run"