Mercurial > hgrepos > Python > apps > py-cutils
comparison cutils/treesum.py @ 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 |
comparison
equal
deleted
inserted
replaced
| 150:f84cf853da22 | 151:b26c4290e928 |
|---|---|
| 75 "empty use it as the leading \"ROOT (<TAG>)\" output.") | 75 "empty use it as the leading \"ROOT (<TAG>)\" output.") |
| 76 gp.add_argument( | 76 gp.add_argument( |
| 77 "--mmap", action="store_true", dest="mmap", default=None, | 77 "--mmap", action="store_true", dest="mmap", default=None, |
| 78 help="Use mmap if available. Default is to determine " | 78 help="Use mmap if available. Default is to determine " |
| 79 "automatically from the filesize.") | 79 "automatically from the filesize.") |
| 80 gp.add_argument( | |
| 81 "--mtime", action="store_true", dest="metadata_mtime", | |
| 82 help="Consider the mtime of files (non-directories) when " | |
| 83 "generating digests for directories. Digests for files are " | |
| 84 "not affected.") | |
| 80 gp.add_argument( | 85 gp.add_argument( |
| 81 "--no-mmap", action="store_false", dest="mmap", default=None, | 86 "--no-mmap", action="store_false", dest="mmap", default=None, |
| 82 help="Dont use mmap.") | 87 help="Dont use mmap.") |
| 83 gp.add_argument( | 88 gp.add_argument( |
| 84 "--output", "-o", action="store", metavar="OUTPUT", | 89 "--output", "-o", action="store", metavar="OUTPUT", |
| 182 comment=[], | 187 comment=[], |
| 183 follow_directory_symlinks=False, | 188 follow_directory_symlinks=False, |
| 184 logical=None, | 189 logical=None, |
| 185 minimal=None, | 190 minimal=None, |
| 186 mmap=None, | 191 mmap=None, |
| 192 mtime=False, | |
| 187 output=None): | 193 output=None): |
| 188 opts = argparse.Namespace( | 194 opts = argparse.Namespace( |
| 189 directories=directories, | 195 directories=directories, |
| 190 algorithm=(util.algotag2algotype(algorithm), | 196 algorithm=(util.algotag2algotype(algorithm), |
| 191 algorithm), | 197 algorithm), |
| 194 comment=comment, | 200 comment=comment, |
| 195 follow_directory_symlinks=follow_directory_symlinks, | 201 follow_directory_symlinks=follow_directory_symlinks, |
| 196 logical=logical, | 202 logical=logical, |
| 197 minimal=minimal, | 203 minimal=minimal, |
| 198 mmap=mmap, | 204 mmap=mmap, |
| 205 metadata_mtime=mtime, | |
| 199 output=output) | 206 output=output) |
| 200 return opts | 207 return opts |
| 201 | 208 |
| 202 | 209 |
| 203 def treesum(opts): | 210 def treesum(opts): |
| 230 with out_cm as outfp: | 237 with out_cm as outfp: |
| 231 for d in opts.directories: | 238 for d in opts.directories: |
| 232 generate_treesum_for_directory( | 239 generate_treesum_for_directory( |
| 233 outfp, d, opts.algorithm, opts.mmap, opts.base64, opts.logical, | 240 outfp, d, opts.algorithm, opts.mmap, opts.base64, opts.logical, |
| 234 opts.follow_directory_symlinks, | 241 opts.follow_directory_symlinks, |
| 242 opts.metadata_mtime, | |
| 235 minimal=opts.minimal, | 243 minimal=opts.minimal, |
| 236 comment=opts.comment) | 244 comment=opts.comment) |
| 237 | 245 |
| 238 | 246 |
| 239 def generate_treesum_for_directory( | 247 def generate_treesum_for_directory( |
| 240 outfp, root, algorithm, use_mmap, use_base64, handle_root_logical, | 248 outfp, root, algorithm, use_mmap, use_base64, handle_root_logical, |
| 241 follow_directory_symlinks, minimal=None, comment=None): | 249 follow_directory_symlinks, with_metadata_mtime, |
| 250 minimal=None, comment=None): | |
| 242 """ | 251 """ |
| 243 | 252 |
| 244 :param outfp: a *binary* file with a "write()" and a "flush()" method | 253 :param outfp: a *binary* file with a "write()" and a "flush()" method |
| 245 | 254 |
| 246 """ | 255 """ |
| 247 outfp.write(format_bsd_line("VERSION", "1", None, False)) | 256 outfp.write(format_bsd_line("VERSION", "1", None, False)) |
| 248 outfp.flush() | 257 outfp.flush() |
| 249 | 258 |
| 250 # Note given non-default flags that are relevant for directory traversal | 259 # Note given non-default flags that are relevant for directory traversal |
| 251 flags = [] | 260 flags = [] |
| 261 if with_metadata_mtime: | |
| 262 flags.append("with-metadata-mtime") | |
| 252 if handle_root_logical: | 263 if handle_root_logical: |
| 253 flags.append("logical") | 264 flags.append("logical") |
| 254 if follow_directory_symlinks: | 265 if follow_directory_symlinks: |
| 255 flags.append("follow-directory-symlinks") | 266 flags.append("follow-directory-symlinks") |
| 256 if flags: | 267 if flags: |
| 319 dgst = dir_digests[top + (dn.name,)] | 330 dgst = dir_digests[top + (dn.name,)] |
| 320 dir_dgst.update(b"1:d,%d:%s," % (len(dn.fsname), dn.fsname)) | 331 dir_dgst.update(b"1:d,%d:%s," % (len(dn.fsname), dn.fsname)) |
| 321 dir_dgst.update(dgst) | 332 dir_dgst.update(dgst) |
| 322 for fn in nondirs: | 333 for fn in nondirs: |
| 323 dir_dgst.update(b"1:f,%d:%s," % (len(fn.fsname), fn.fsname)) | 334 dir_dgst.update(b"1:f,%d:%s," % (len(fn.fsname), fn.fsname)) |
| 335 if with_metadata_mtime: | |
| 336 mtime = datetime.datetime.utcfromtimestamp( | |
| 337 int(fn.stat.st_mtime)) | |
| 338 mtime = mtime.isoformat("T") + "Z" | |
| 339 if not isinstance(mtime, bytes): | |
| 340 mtime = mtime.encode("ascii") | |
| 341 dir_dgst.update(b"5:mtime,%d:%s," % (len(mtime), mtime)) | |
| 324 dgst = digest.compute_digest_file( | 342 dgst = digest.compute_digest_file( |
| 325 algorithm[0], fn.path, use_mmap=use_mmap) | 343 algorithm[0], fn.path, use_mmap=use_mmap) |
| 326 dir_dgst.update(dgst) | 344 dir_dgst.update(dgst) |
| 327 opath = "/".join(top) + "/" + fn.name if top else fn.name | 345 opath = "/".join(top) + "/" + fn.name if top else fn.name |
| 328 outfp.write( | 346 outfp.write( |
