Browse Source

move diff command to archiver.diff

Thomas Waldmann 2 years ago
parent
commit
9fb224db6b
3 changed files with 131 additions and 101 deletions
  1. 1 0
      setup.cfg
  2. 12 101
      src/borg/archiver/__init__.py
  3. 118 0
      src/borg/archiver/diff.py

+ 1 - 0
setup.cfg

@@ -121,6 +121,7 @@ per_file_ignores =
     src/borg/archiver/config.py:F405,E722
     src/borg/archiver/common.py:E501,F405
     src/borg/archiver/debug.py:F405
+    src/borg/archiver/diff.py:F405
     src/borg/archiver/help.py:E501,F405
     src/borg/archiver/keys.py:F405
     src/borg/archiver/prune.py:F405

+ 12 - 101
src/borg/archiver/__init__.py

@@ -100,6 +100,7 @@ def get_func(args):
 from .benchmarks import BenchmarkMixIn
 from .config import ConfigMixIn
 from .debug import DebugMixIn
+from .diff import DiffMixIn
 from .help import HelpMixIn
 from .keys import KeysMixIn
 from .locks import LocksMixIn
@@ -109,7 +110,16 @@ from .transfer import TransferMixIn
 
 
 class Archiver(
-    ConfigMixIn, DebugMixIn, TarMixIn, BenchmarkMixIn, KeysMixIn, LocksMixIn, PruneMixIn, HelpMixIn, TransferMixIn
+    ConfigMixIn,
+    DebugMixIn,
+    DiffMixIn,
+    TarMixIn,
+    BenchmarkMixIn,
+    KeysMixIn,
+    LocksMixIn,
+    PruneMixIn,
+    HelpMixIn,
+    TransferMixIn,
 ):
     def __init__(self, lock_wait=None, prog=None):
         self.exit_code = EXIT_SUCCESS
@@ -774,50 +784,6 @@ class Archiver(
             pi.finish()
         return self.exit_code
 
-    @with_repository(compatibility=(Manifest.Operation.READ,))
-    @with_archive
-    def do_diff(self, args, repository, manifest, key, archive):
-        """Diff contents of two archives"""
-
-        def print_json_output(diff, path):
-            print(json.dumps({"path": path, "changes": [j for j, str in diff]}))
-
-        def print_text_output(diff, path):
-            print("{:<19} {}".format(" ".join([str for j, str in diff]), path))
-
-        print_output = print_json_output if args.json_lines else print_text_output
-
-        archive1 = archive
-        archive2 = Archive(repository, key, manifest, args.other_name, consider_part_files=args.consider_part_files)
-
-        can_compare_chunk_ids = (
-            archive1.metadata.get("chunker_params", False) == archive2.metadata.get("chunker_params", True)
-            or args.same_chunker_params
-        )
-        if not can_compare_chunk_ids:
-            self.print_warning(
-                "--chunker-params might be different between archives, diff will be slow.\n"
-                "If you know for certain that they are the same, pass --same-chunker-params "
-                "to override this check."
-            )
-
-        matcher = self.build_matcher(args.patterns, args.paths)
-
-        diffs = Archive.compare_archives_iter(archive1, archive2, matcher, can_compare_chunk_ids=can_compare_chunk_ids)
-        # Conversion to string and filtering for diff.equal to save memory if sorting
-        diffs = ((path, diff.changes()) for path, diff in diffs if not diff.equal)
-
-        if args.sort:
-            diffs = sorted(diffs)
-
-        for path, diff in diffs:
-            print_output(diff, path)
-
-        for pattern in matcher.get_unmatched_include_patterns():
-            self.print_warning("Include pattern '%s' never matched.", pattern)
-
-        return self.exit_code
-
     @with_repository(exclusive=True, cache=True, compatibility=(Manifest.Operation.CHECK,))
     @with_archive
     def do_rename(self, args, repository, manifest, key, cache, archive):
@@ -1627,6 +1593,7 @@ class Archiver(
         subparsers = parser.add_subparsers(title="required arguments", metavar="<command>")
 
         self.build_parser_benchmarks(subparsers, common_parser, mid_common_parser)
+        self.build_parser_diff(subparsers, common_parser, mid_common_parser)
         self.build_parser_locks(subparsers, common_parser, mid_common_parser)
         self.build_parser_prune(subparsers, common_parser, mid_common_parser)
 
@@ -2287,62 +2254,6 @@ class Archiver(
         )
         define_archive_filters_group(subparser)
 
-        # borg diff
-        diff_epilog = process_epilog(
-            """
-            This command finds differences (file contents, user/group/mode) between archives.
-
-            A repository location and an archive name must be specified for REPO::ARCHIVE1.
-            ARCHIVE2 is just another archive name in same repository (no repository location
-            allowed).
-
-            For archives created with Borg 1.1 or newer diff automatically detects whether
-            the archives are created with the same chunker params. If so, only chunk IDs
-            are compared, which is very fast.
-
-            For archives prior to Borg 1.1 chunk contents are compared by default.
-            If you did not create the archives with different chunker params,
-            pass ``--same-chunker-params``.
-            Note that the chunker params changed from Borg 0.xx to 1.0.
-
-            For more help on include/exclude patterns, see the :ref:`borg_patterns` command output.
-            """
-        )
-        subparser = subparsers.add_parser(
-            "diff",
-            parents=[common_parser],
-            add_help=False,
-            description=self.do_diff.__doc__,
-            epilog=diff_epilog,
-            formatter_class=argparse.RawDescriptionHelpFormatter,
-            help="find differences in archive contents",
-        )
-        subparser.set_defaults(func=self.do_diff)
-        subparser.add_argument(
-            "--numeric-ids",
-            dest="numeric_ids",
-            action="store_true",
-            help="only consider numeric user and group identifiers",
-        )
-        subparser.add_argument(
-            "--same-chunker-params",
-            dest="same_chunker_params",
-            action="store_true",
-            help="Override check of chunker parameters.",
-        )
-        subparser.add_argument("--sort", dest="sort", action="store_true", help="Sort the output lines by file path.")
-        subparser.add_argument("--json-lines", action="store_true", help="Format output as JSON Lines. ")
-        subparser.add_argument("name", metavar="ARCHIVE1", type=archivename_validator(), help="ARCHIVE1 name")
-        subparser.add_argument("other_name", metavar="ARCHIVE2", type=archivename_validator(), help="ARCHIVE2 name")
-        subparser.add_argument(
-            "paths",
-            metavar="PATH",
-            nargs="*",
-            type=str,
-            help="paths of items inside the archives to compare; patterns are supported",
-        )
-        define_exclusion_group(subparser)
-
         # borg extract
         extract_epilog = process_epilog(
             """

+ 118 - 0
src/borg/archiver/diff.py

@@ -0,0 +1,118 @@
+import argparse
+import json
+
+from .common import with_repository, with_archive
+from ..archive import Archive
+from ..constants import *  # NOQA
+from ..helpers import archivename_validator
+from ..helpers import Manifest
+
+from ..logger import create_logger
+
+logger = create_logger()
+
+
+class DiffMixIn:
+    @with_repository(compatibility=(Manifest.Operation.READ,))
+    @with_archive
+    def do_diff(self, args, repository, manifest, key, archive):
+        """Diff contents of two archives"""
+
+        def print_json_output(diff, path):
+            print(json.dumps({"path": path, "changes": [j for j, str in diff]}))
+
+        def print_text_output(diff, path):
+            print("{:<19} {}".format(" ".join([str for j, str in diff]), path))
+
+        print_output = print_json_output if args.json_lines else print_text_output
+
+        archive1 = archive
+        archive2 = Archive(repository, key, manifest, args.other_name, consider_part_files=args.consider_part_files)
+
+        can_compare_chunk_ids = (
+            archive1.metadata.get("chunker_params", False) == archive2.metadata.get("chunker_params", True)
+            or args.same_chunker_params
+        )
+        if not can_compare_chunk_ids:
+            self.print_warning(
+                "--chunker-params might be different between archives, diff will be slow.\n"
+                "If you know for certain that they are the same, pass --same-chunker-params "
+                "to override this check."
+            )
+
+        matcher = self.build_matcher(args.patterns, args.paths)
+
+        diffs = Archive.compare_archives_iter(archive1, archive2, matcher, can_compare_chunk_ids=can_compare_chunk_ids)
+        # Conversion to string and filtering for diff.equal to save memory if sorting
+        diffs = ((path, diff.changes()) for path, diff in diffs if not diff.equal)
+
+        if args.sort:
+            diffs = sorted(diffs)
+
+        for path, diff in diffs:
+            print_output(diff, path)
+
+        for pattern in matcher.get_unmatched_include_patterns():
+            self.print_warning("Include pattern '%s' never matched.", pattern)
+
+        return self.exit_code
+
+    def build_parser_diff(self, subparsers, common_parser, mid_common_parser):
+
+        from .common import process_epilog
+        from .common import define_exclusion_group
+
+        diff_epilog = process_epilog(
+            """
+            This command finds differences (file contents, user/group/mode) between archives.
+
+            A repository location and an archive name must be specified for REPO::ARCHIVE1.
+            ARCHIVE2 is just another archive name in same repository (no repository location
+            allowed).
+
+            For archives created with Borg 1.1 or newer diff automatically detects whether
+            the archives are created with the same chunker params. If so, only chunk IDs
+            are compared, which is very fast.
+
+            For archives prior to Borg 1.1 chunk contents are compared by default.
+            If you did not create the archives with different chunker params,
+            pass ``--same-chunker-params``.
+            Note that the chunker params changed from Borg 0.xx to 1.0.
+
+            For more help on include/exclude patterns, see the :ref:`borg_patterns` command output.
+            """
+        )
+        subparser = subparsers.add_parser(
+            "diff",
+            parents=[common_parser],
+            add_help=False,
+            description=self.do_diff.__doc__,
+            epilog=diff_epilog,
+            formatter_class=argparse.RawDescriptionHelpFormatter,
+            help="find differences in archive contents",
+        )
+        subparser.set_defaults(func=self.do_diff)
+        subparser.add_argument(
+            "--numeric-ids",
+            dest="numeric_ids",
+            action="store_true",
+            help="only consider numeric user and group identifiers",
+        )
+        subparser.add_argument(
+            "--same-chunker-params",
+            dest="same_chunker_params",
+            action="store_true",
+            help="Override check of chunker parameters.",
+        )
+        subparser.add_argument("--sort", dest="sort", action="store_true", help="Sort the output lines by file path.")
+        subparser.add_argument("--json-lines", action="store_true", help="Format output as JSON Lines. ")
+        subparser.add_argument("name", metavar="ARCHIVE1", type=archivename_validator(), help="ARCHIVE1 name")
+        subparser.add_argument("other_name", metavar="ARCHIVE2", type=archivename_validator(), help="ARCHIVE2 name")
+        subparser.add_argument(
+            "paths",
+            metavar="PATH",
+            nargs="*",
+            type=str,
+            help="paths of items inside the archives to compare; patterns are supported",
+        )
+        define_exclusion_group(subparser)