changeset 151:b26c4290e928

Implement "--mtime" for treesum to include a file's mtime in a directory digest. Pure file diests are not affected.
author Franz Glasner <fzglas.hg@dom66.de>
date Fri, 03 Jan 2025 23:33:37 +0100
parents f84cf853da22
children 46cb438fa520
files cutils/treesum.py
diffstat 1 files changed, 19 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/cutils/treesum.py	Fri Jan 03 23:08:02 2025 +0100
+++ b/cutils/treesum.py	Fri Jan 03 23:33:37 2025 +0100
@@ -78,6 +78,11 @@
             help="Use mmap if available. Default is to determine "
                  "automatically from the filesize.")
         gp.add_argument(
+            "--mtime", action="store_true", dest="metadata_mtime",
+            help="Consider the mtime of files (non-directories) when "
+                 "generating digests for directories. Digests for files are "
+                 "not affected.")
+        gp.add_argument(
             "--no-mmap", action="store_false", dest="mmap", default=None,
             help="Dont use mmap.")
         gp.add_argument(
@@ -184,6 +189,7 @@
                       logical=None,
                       minimal=None,
                       mmap=None,
+                      mtime=False,
                       output=None):
     opts = argparse.Namespace(
         directories=directories,
@@ -196,6 +202,7 @@
         logical=logical,
         minimal=minimal,
         mmap=mmap,
+        metadata_mtime=mtime,
         output=output)
     return opts
 
@@ -232,13 +239,15 @@
             generate_treesum_for_directory(
                 outfp, d, opts.algorithm, opts.mmap, opts.base64, opts.logical,
                 opts.follow_directory_symlinks,
+                opts.metadata_mtime,
                 minimal=opts.minimal,
                 comment=opts.comment)
 
 
 def generate_treesum_for_directory(
         outfp, root, algorithm, use_mmap, use_base64, handle_root_logical,
-        follow_directory_symlinks, minimal=None, comment=None):
+        follow_directory_symlinks, with_metadata_mtime,
+        minimal=None, comment=None):
     """
 
     :param outfp: a *binary* file with a "write()" and a "flush()" method
@@ -249,6 +258,8 @@
 
     # Note given non-default flags that are relevant for directory traversal
     flags = []
+    if with_metadata_mtime:
+        flags.append("with-metadata-mtime")
     if handle_root_logical:
         flags.append("logical")
     if follow_directory_symlinks:
@@ -321,6 +332,13 @@
             dir_dgst.update(dgst)
         for fn in nondirs:
             dir_dgst.update(b"1:f,%d:%s," % (len(fn.fsname), fn.fsname))
+            if with_metadata_mtime:
+                mtime = datetime.datetime.utcfromtimestamp(
+                    int(fn.stat.st_mtime))
+                mtime = mtime.isoformat("T") + "Z"
+                if not isinstance(mtime, bytes):
+                    mtime = mtime.encode("ascii")
+                dir_dgst.update(b"5:mtime,%d:%s," % (len(mtime), mtime))
             dgst = digest.compute_digest_file(
                 algorithm[0], fn.path, use_mmap=use_mmap)
             dir_dgst.update(dgst)