Mercurial > hgrepos > Python > apps > py-cutils
comparison cutils/treesum.py @ 158:d8cdd1985d43
Implement "--full-mode" for "treesum.py"
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Tue, 07 Jan 2025 12:48:37 +0100 |
| parents | 27d1aaf5fe39 |
| children | 5c23ad9a3f8f |
comparison
equal
deleted
inserted
replaced
| 157:27d1aaf5fe39 | 158:d8cdd1985d43 |
|---|---|
| 63 help="Follow symbolic links to directories when walking a " | 63 help="Follow symbolic links to directories when walking a " |
| 64 "directory tree. Note that this is different from using " | 64 "directory tree. Note that this is different from using " |
| 65 "\"--logical\" or \"--physical\" for arguments given " | 65 "\"--logical\" or \"--physical\" for arguments given " |
| 66 "directly on the command line") | 66 "directly on the command line") |
| 67 gp.add_argument( | 67 gp.add_argument( |
| 68 "--full-mode", action="store_true", dest="metadata_full_mode", | |
| 69 help="Consider all mode bits as returned from stat(2) when " | |
| 70 "computing directory digests. " | |
| 71 "Note that mode bits on symbolic links itself are not " | |
| 72 "considered.") | |
| 73 gp.add_argument( | |
| 68 "--logical", "-L", dest="logical", action="store_true", | 74 "--logical", "-L", dest="logical", action="store_true", |
| 69 default=None, | 75 default=None, |
| 70 help="Follow symbolic links given on command line arguments." | 76 help="Follow symbolic links given on command line arguments." |
| 71 " Note that this is a different setting as to follow symbolic" | 77 " Note that this is a different setting as to follow symbolic" |
| 72 " links to directories when traversing a directory tree.") | 78 " links to directories when traversing a directory tree.") |
| 78 "--mmap", action="store_true", dest="mmap", default=None, | 84 "--mmap", action="store_true", dest="mmap", default=None, |
| 79 help="Use mmap if available. Default is to determine " | 85 help="Use mmap if available. Default is to determine " |
| 80 "automatically from the filesize.") | 86 "automatically from the filesize.") |
| 81 gp.add_argument( | 87 gp.add_argument( |
| 82 "--mode", action="store_true", dest="metadata_mode", | 88 "--mode", action="store_true", dest="metadata_mode", |
| 83 help="Consider the permission bits of stat using S_IMODE (i.e. " | 89 help="Consider the permission bits of stat(2) using S_IMODE (i.e. " |
| 84 "all bits without the filetype bits) when " | 90 "all bits without the filetype bits) when " |
| 85 "computing directory digests. Note that symbolic links " | 91 "computing directory digests. Note that mode bits on " |
| 86 "are not considered.") | 92 "symbolic links itself are not considered.") |
| 87 gp.add_argument( | 93 gp.add_argument( |
| 88 "--mtime", action="store_true", dest="metadata_mtime", | 94 "--mtime", action="store_true", dest="metadata_mtime", |
| 89 help="Consider the mtime of files (non-directories) when " | 95 help="Consider the mtime of files (non-directories) when " |
| 90 "generating digests for directories. Digests for files are " | 96 "generating digests for directories. Digests for files are " |
| 91 "not affected.") | 97 "not affected.") |
| 192 algorithm="BLAKE2b-256", | 198 algorithm="BLAKE2b-256", |
| 193 append_output=False, | 199 append_output=False, |
| 194 base64=False, | 200 base64=False, |
| 195 comment=[], | 201 comment=[], |
| 196 follow_directory_symlinks=False, | 202 follow_directory_symlinks=False, |
| 203 full_mode=False, | |
| 197 logical=None, | 204 logical=None, |
| 198 minimal=None, | 205 minimal=None, |
| 199 mode=False, | 206 mode=False, |
| 200 mmap=None, | 207 mmap=None, |
| 201 mtime=False, | 208 mtime=False, |
| 209 comment=comment, | 216 comment=comment, |
| 210 follow_directory_symlinks=follow_directory_symlinks, | 217 follow_directory_symlinks=follow_directory_symlinks, |
| 211 logical=logical, | 218 logical=logical, |
| 212 minimal=minimal, | 219 minimal=minimal, |
| 213 mmap=mmap, | 220 mmap=mmap, |
| 221 metadata_full_mode=full_mode, | |
| 214 metadata_mode=mode, | 222 metadata_mode=mode, |
| 215 metadata_mtime=mtime, | 223 metadata_mtime=mtime, |
| 216 output=output) | 224 output=output) |
| 217 return opts | 225 return opts |
| 218 | 226 |
| 248 for d in opts.directories: | 256 for d in opts.directories: |
| 249 generate_treesum_for_directory( | 257 generate_treesum_for_directory( |
| 250 outfp, d, opts.algorithm, opts.mmap, opts.base64, opts.logical, | 258 outfp, d, opts.algorithm, opts.mmap, opts.base64, opts.logical, |
| 251 opts.follow_directory_symlinks, | 259 opts.follow_directory_symlinks, |
| 252 opts.metadata_mode, | 260 opts.metadata_mode, |
| 261 opts.metadata_full_mode, | |
| 253 opts.metadata_mtime, | 262 opts.metadata_mtime, |
| 254 minimal=opts.minimal, | 263 minimal=opts.minimal, |
| 255 comment=opts.comment) | 264 comment=opts.comment) |
| 256 | 265 |
| 257 | 266 |
| 258 def generate_treesum_for_directory( | 267 def generate_treesum_for_directory( |
| 259 outfp, root, algorithm, use_mmap, use_base64, handle_root_logical, | 268 outfp, root, algorithm, use_mmap, use_base64, handle_root_logical, |
| 260 follow_directory_symlinks, with_metadata_mode, with_metadata_mtime, | 269 follow_directory_symlinks, with_metadata_mode, with_metadata_full_mode, |
| 270 with_metadata_mtime, | |
| 261 minimal=None, comment=None): | 271 minimal=None, comment=None): |
| 262 """ | 272 """ |
| 263 | 273 |
| 264 :param outfp: a *binary* file with a "write()" and a "flush()" method | 274 :param outfp: a *binary* file with a "write()" and a "flush()" method |
| 265 | 275 |
| 320 for top, fsobjects in walk.walk( | 330 for top, fsobjects in walk.walk( |
| 321 root, | 331 root, |
| 322 follow_symlinks=follow_directory_symlinks): | 332 follow_symlinks=follow_directory_symlinks): |
| 323 dir_dgst = algorithm[0]() | 333 dir_dgst = algorithm[0]() |
| 324 for fso in fsobjects: | 334 for fso in fsobjects: |
| 325 # print("NNNNNNNN", fso.name, fso.stat, | 335 print("NNNNNNNN", fso.name, fso.stat, |
| 326 # "%o (%o)" % (fso.stat.st_mode, stat.S_IMODE(fso.stat.st_mode))) | 336 "%o (%o)" |
| 337 % (fso.stat.st_mode, stat.S_IMODE(fso.stat.st_mode))) | |
| 327 if fso.is_dir: | 338 if fso.is_dir: |
| 328 if fso.is_symlink and not follow_directory_symlinks: | 339 if fso.is_symlink and not follow_directory_symlinks: |
| 329 linktgt = util.fsencode(os.readlink(fso.path)) | 340 linktgt = util.fsencode(os.readlink(fso.path)) |
| 330 linkdgst = algorithm[0]() | 341 linkdgst = algorithm[0]() |
| 331 linkdgst.update(b"%d:%s," % (len(linktgt), linktgt)) | 342 linkdgst.update(b"%d:%s," % (len(linktgt), linktgt)) |
| 344 continue | 355 continue |
| 345 # fetch from dir_digests | 356 # fetch from dir_digests |
| 346 dgst = dir_digests[top + (fso.name,)] | 357 dgst = dir_digests[top + (fso.name,)] |
| 347 dir_dgst.update(b"1:d,%d:%s," % (len(fso.fsname), fso.fsname)) | 358 dir_dgst.update(b"1:d,%d:%s," % (len(fso.fsname), fso.fsname)) |
| 348 dir_dgst.update(dgst) | 359 dir_dgst.update(dgst) |
| 349 if with_metadata_mode: | 360 if with_metadata_full_mode: |
| 350 modestr = normalized_mode_str(fso.stat.st_mode) | 361 modestr = normalized_mode_str(fso.stat.st_mode) |
| 362 if not isinstance(modestr, bytes): | |
| 363 modestr = modestr.encode("ascii") | |
| 364 dir_dgst.update(b"8:fullmode,%d:%s," | |
| 365 % (len(modestr), modestr)) | |
| 366 elif with_metadata_mode: | |
| 367 modestr = normalized_compatible_mode_str(fso.stat.st_mode) | |
| 351 if not isinstance(modestr, bytes): | 368 if not isinstance(modestr, bytes): |
| 352 modestr = modestr.encode("ascii") | 369 modestr = modestr.encode("ascii") |
| 353 dir_dgst.update(b"4:mode,%d:%s," % (len(modestr), modestr)) | 370 dir_dgst.update(b"4:mode,%d:%s," % (len(modestr), modestr)) |
| 354 else: | 371 else: |
| 355 dir_dgst.update(b"1:f,%d:%s," % (len(fso.fsname), fso.fsname)) | 372 dir_dgst.update(b"1:f,%d:%s," % (len(fso.fsname), fso.fsname)) |
| 358 int(fso.stat.st_mtime)) | 375 int(fso.stat.st_mtime)) |
| 359 mtime = mtime.isoformat("T") + "Z" | 376 mtime = mtime.isoformat("T") + "Z" |
| 360 if not isinstance(mtime, bytes): | 377 if not isinstance(mtime, bytes): |
| 361 mtime = mtime.encode("ascii") | 378 mtime = mtime.encode("ascii") |
| 362 dir_dgst.update(b"5:mtime,%d:%s," % (len(mtime), mtime)) | 379 dir_dgst.update(b"5:mtime,%d:%s," % (len(mtime), mtime)) |
| 363 if with_metadata_mode: | 380 if with_metadata_full_mode: |
| 364 modestr = normalized_mode_str(fso.stat.st_mode) | 381 modestr = normalized_mode_str(fso.stat.st_mode) |
| 382 if not isinstance(modestr, bytes): | |
| 383 modestr = modestr.encode("ascii") | |
| 384 dir_dgst.update(b"8:fullmode,%d:%s," | |
| 385 % (len(modestr), modestr)) | |
| 386 elif with_metadata_mode: | |
| 387 modestr = normalized_compatible_mode_str(fso.stat.st_mode) | |
| 365 if not isinstance(modestr, bytes): | 388 if not isinstance(modestr, bytes): |
| 366 modestr = modestr.encode("ascii") | 389 modestr = modestr.encode("ascii") |
| 367 dir_dgst.update(b"4:mode,%d:%s," % (len(modestr), modestr)) | 390 dir_dgst.update(b"4:mode,%d:%s," % (len(modestr), modestr)) |
| 368 dgst = digest.compute_digest_file( | 391 dgst = digest.compute_digest_file( |
| 369 algorithm[0], fso.path, use_mmap=use_mmap) | 392 algorithm[0], fso.path, use_mmap=use_mmap) |
| 378 algorithm[1], dir_dgst.digest(), opath, use_base64)) | 401 algorithm[1], dir_dgst.digest(), opath, use_base64)) |
| 379 outfp.flush() | 402 outfp.flush() |
| 380 dir_digests[top] = dir_dgst.digest() | 403 dir_digests[top] = dir_dgst.digest() |
| 381 | 404 |
| 382 | 405 |
| 383 def normalized_mode_str(mode): | 406 def normalized_compatible_mode_str(mode): |
| 384 # XXX FIXME: Windows and "executable" | 407 # XXX FIXME: Windows and "executable" |
| 385 modebits = stat.S_IMODE(mode) | 408 modebits = stat.S_IMODE(mode) |
| 386 modestr = "%o" % (modebits,) | 409 modestr = "%o" % (modebits,) |
| 410 if not modestr.startswith("0"): | |
| 411 modestr = "0" + modestr | |
| 412 return modestr | |
| 413 | |
| 414 | |
| 415 def normalized_mode_str(mode): | |
| 416 modestr = "%o" % (mode,) | |
| 387 if not modestr.startswith("0"): | 417 if not modestr.startswith("0"): |
| 388 modestr = "0" + modestr | 418 modestr = "0" + modestr |
| 389 return modestr | 419 return modestr |
| 390 | 420 |
| 391 | 421 |
