changeset 190:7e0c25a31757

First implementation of "treeview info" to print some information from the treeview digest files
author Franz Glasner <fzglas.hg@dom66.de>
date Thu, 16 Jan 2025 11:29:36 +0100
parents 959c6d37b014
children 1b8bc876146a
files cutils/treesum.py
diffstat 1 files changed, 111 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/cutils/treesum.py	Wed Jan 15 15:40:46 2025 +0100
+++ b/cutils/treesum.py	Thu Jan 16 11:29:36 2025 +0100
@@ -128,6 +128,16 @@
         gp.add_argument(
             "directories", nargs="*", metavar="DIRECTORY")
 
+    def _populate_info_arguments(ip):
+        ip.add_argument(
+            "--debug", action="store_true",
+            help="Activate debug logging to stderr")
+        ip.add_argument(
+            "--last", action="store_true", dest="print_only_last_block",
+            help="Print only the last block of every given input file")
+        ip.add_argument(
+            "digest_files", nargs="+", metavar="TREESUM-DIGEST-FILE")
+
     parser = argparse.ArgumentParser(
         description="Generate and verify checksums for directory trees.",
         fromfile_prefix_chars='@',
@@ -161,8 +171,8 @@
 
     genparser = subparsers.add_parser(
         "generate",
-        help="Generate checksums for directory trees.",
-        description="Generate checksums for directory trees")
+        help="Generate checksums for directory trees",
+        description="Generate checksums for directory trees.")
     _populate_generate_arguments(genparser)
     # And an alias for "generate"
     genparser2 = subparsers.add_parser(
@@ -172,6 +182,14 @@
                     "This is an alias to \"generate\".")
     _populate_generate_arguments(genparser2)
 
+    infoparser = subparsers.add_parser(
+        "info",
+        help="Print some information from given treesum digest file",
+        description="""Print some informations from given treesum digest files
+to stdout."""
+    )
+    _populate_info_arguments(infoparser)
+
     hparser = subparsers.add_parser(
         "help",
         help="Show this help message or a subcommand's help and exit",
@@ -198,6 +216,8 @@
                 genparser.print_help()
             elif opts.help_command == "gen":
                 genparser2.print_help()
+            elif opts.help_command == "info":
+                infoparser.print_help()
             elif opts.help_command == "version":
                 vparser.print_help()
             elif opts.help_command == "help":
@@ -254,10 +274,19 @@
     return opts
 
 
+def gen_info_opts(digest_files=[], last=False):
+    opts = argparse.Namespace(
+        digest_files=digest_files,
+        print_only_last_block=last)
+    return opts
+
+
 def treesum(opts):
     # XXX TBD: opts.check and opts.checklist (as in shasum.py)
     if opts.subcommand in ("generate", "gen"):
         return generate_treesum(opts)
+    elif opts.subcommand == "info":
+        return print_treesum_digestfile_infos(opts)
     else:
         raise RuntimeError(
             "command `{}' not yet handled".format(opts.subcommand))
@@ -817,5 +846,85 @@
         return self._current_algo_digest_size
 
 
+def print_treesum_digestfile_infos(opts):
+    print_infos_for_digestfile(opts.digest_files, opts.print_only_last_block)
+
+
+def print_infos_for_digestfile(digest_files, print_only_last_block=True):
+    for fn in digest_files:
+        if fn == "-":
+            if util.PY2:
+                reader = TreesumReader.from_binary_buffer(sys.stdin)
+            else:
+                reader = TreesumReader.from_binary_buffer(sys.stdin.buffer)
+        else:
+            reader = TreesumReader.from_path(fn)
+
+        with reader:
+            root = flags = algorithm = digest = size = None
+            comments = []
+            in_block = False
+            block_no = 0
+            for record in reader:
+                if record[0] == "VERSION":
+                    assert record[1] == "1"
+                    # start a new block
+                    in_block = True
+                    block_no += 1
+                    root = flags = algorithm = digest = size = None
+                    comments = []
+                elif record[0] == "FLAGS":
+                    flags = record[1]
+                elif record[0] == "ROOT":
+                    root = record[1]
+                elif record[0] == "COMMENT":
+                    comments.append(record[1])
+                elif record[0] in ("TIMESTAMP", "ISOTIMESTAMP"):
+                    pass
+                elif record[0] == "CRC32":
+                    pass
+                    # in_block = False
+                else:
+                    if not in_block:
+                        continue
+                    # digest line or size line
+                    if not record[1] or record[1] == b"./@":
+                        if record[0] == "SIZE":
+                            algorithm = "SIZE"
+                            digest = None
+                            size = record[2]
+                        else:
+                            algorithm = record[0]
+                            digest = record[2]
+                            size = record[3]
+                        if not print_only_last_block:
+                            print_block_data(
+                                block_no,
+                                root, flags, comments, algorithm, digest, size)
+                            root = flags = algorithm = digest = size = None
+                        in_block = False
+        if print_only_last_block:
+            if not in_block:
+                if digest is not None or size is not None:
+                    print_block_data(
+                        block_no,
+                        root, flags, comments, algorithm, digest, size)
+            else:
+                logging.warning("missing block end")
+
+
+def print_block_data(block_no, tag, flags, comments, algorithm, digest, size):
+    digeststr = util.n(binascii.hexlify(digest)) if digest else "<no digest>"
+    sizestr = str(size) if size is not None else "<no size>"
+    print("BLOCK No %d:" % (block_no,))
+    print("    Tag:", tag)
+    print("    Flags:", flags if flags else "<none>")
+    print("    Comments:", comments if comments else "")
+    print("    Algorithm:", algorithm)
+    if algorithm != "SIZE":
+        print("    Digest:", digeststr)
+    print("    Size:", sizestr)
+
+
 if __name__ == "__main__":
     sys.exit(main())