diff cutils/treesum.py @ 205:63088d3675bb

Add a "GENERATOR" line with control flats to treesum.py
author Franz Glasner <fzglas.hg@dom66.de>
date Wed, 22 Jan 2025 17:45:37 +0100
parents 07f1d79e6674
children 73d22943da5a
line wrap: on
line diff
--- a/cutils/treesum.py	Tue Jan 21 20:31:48 2025 +0100
+++ b/cutils/treesum.py	Wed Jan 22 17:45:37 2025 +0100
@@ -76,6 +76,13 @@
                  "Note that mode bits on symbolic links itself are not "
                  "considered.")
         gp.add_argument(
+            "--generator", choices=("normal", "full", "none"),
+            default="normal",
+            help="""Put a `GENERATOR' line into the output.
+`full' prints full Python and OS/platform version information,
+`normal' prints just whether Python 2 or Python 3 is used, and `none'
+suppresses the output completely. The default is `normal'.""")
+        gp.add_argument(
             "--logical", "-L", dest="logical", action="store_true",
             default=None,
             help="Follow symbolic links given on command line arguments."
@@ -249,6 +256,7 @@
                       comment=[],
                       follow_directory_symlinks=False,
                       full_mode=False,
+                      generator="normal",
                       logical=None,
                       minimal=None,
                       mode=False,
@@ -265,6 +273,7 @@
         base64=base64,
         comment=comment,
         follow_directory_symlinks=follow_directory_symlinks,
+        generator=generator,
         logical=logical,
         minimal=minimal,
         mmap=mmap,
@@ -321,6 +330,7 @@
             V1DirectoryTreesumGenerator(
                 opts.algorithm, opts.mmap, opts.base64,
                 opts.logical, opts.follow_directory_symlinks,
+                opts.generator,
                 opts.metadata_mode,
                 opts.metadata_full_mode,
                 opts.metadata_mtime,
@@ -335,6 +345,7 @@
 
     def __init__(self, algorithm, use_mmap, use_base64,
                  handle_root_logical, follow_directory_symlinks,
+                 with_generator,
                  with_metadata_mode, with_metadata_full_mode,
                  with_metadata_mtime, size_only, print_size, utf8_mode,
                  minimal=None,):
@@ -344,6 +355,7 @@
         self._use_base64 = use_base64
         self._handle_root_logical = handle_root_logical
         self._follow_directory_symlinks = follow_directory_symlinks
+        self._with_generator = with_generator
         self._with_metadata_mode = with_metadata_mode
         self._with_metadata_full_mode = with_metadata_full_mode
         self._with_metadata_mtime = with_metadata_mtime
@@ -365,6 +377,22 @@
             "FSENCODING", util.n(walk.getfsencoding().upper()), None, False))
         self._outfp.flush()
 
+        if self._with_generator == "none":
+            pass    # do nothing
+        elif self._with_generator == "normal":
+            self._outfp.write(format_bsd_line(
+                "GENERATOR", None, b"PY2" if util.PY2 else b"PY3", False))
+        elif self._with_generator == "full":
+            import platform
+            info = "%s %s, %s" % (platform.python_implementation(),
+                                  platform.python_version(),
+                                  platform.platform())
+            self._outfp.write(format_bsd_line(
+                "GENERATOR", None, info.encode("utf-8"), False))
+        else:
+            raise NotImplementedError(
+                "not implemented: %s" % (self._with_generator,))
+
         #
         # Note: Given non-default flags that are relevant for
         #       directory traversal.
@@ -767,7 +795,7 @@
         assert filename is None
         return util.interpolate_bytes(b"%s = %s%s", what, util.b(value), ls)
     assert filename is not None
-    if what in (b"COMMENT", b"ERROR"):
+    if what in (b"COMMENT", b"ERROR", b"GENERATOR"):
         return util.interpolate_bytes(
             b"%s (%s)%s", what, util.b(filename, "utf-8"), ls)
     if not isinstance(filename, bytes):
@@ -800,7 +828,7 @@
 
     PATTERN0 = re.compile(br"\A[ \t]*\r?\n\Z")   # empty lines
     PATTERN1 = re.compile(br"\A(VERSION|FSENCODING|FLAGS|TIMESTAMP|ISOTIMESTAMP|CRC32)[ \t]*=[ \t]*([^ \t]+)[ \t]*\r?\n\Z")      # noqa: E501  line too long
-    PATTERN2 = re.compile(br"\A(ROOT|COMMENT|ERROR)[ \t]*\((.*)\)[ \t]*\r?\n\Z")                                                 # noqa: E501  line too long
+    PATTERN2 = re.compile(br"\A(ROOT|COMMENT|ERROR|GENERATOR)[ \t]*\((.*)\)[ \t]*\r?\n\Z")                                       # noqa: E501  line too long
     PATTERN3 = re.compile(br"\ASIZE[ \t]*\((.*)\)[ \t]*=[ \t]*(\d+)[ \t]*\r?\n\Z")                                               # noqa: E501  line too long
     PATTERN4 = re.compile(br"\A([A-Za-z0-9_-]+)[ \t]*\((.*)\)[ \t]*=[ \t]*([A-Za-z0-9=+/]+)(,(\d+))?[ \t]*\r?\n\Z")              # noqa: E501  line too long
 
@@ -927,7 +955,7 @@
             mo = self.PATTERN2.search(line)
             if mo:
                 self._update_crc(line)
-                if mo.group(1) in (b"COMMENT", b"ERROR"):
+                if mo.group(1) in (b"COMMENT", b"ERROR", b"GENERATOR"):
                     return (util.u(mo.group(1)), util.u(mo.group(2), "utf-8"))
                 elif mo.group(1) == b"ROOT":
                     return ("ROOT", mo.group(2))