comparison cutils/treesum.py @ 173:e081b6ee5570

treesum.py now runs on Python3.4 also: use a workaround for its missing byte % formatting. No extra module is required for it to run using sha SHA and SHA-2 family of digests.
author Franz Glasner <fzglas.hg@dom66.de>
date Fri, 10 Jan 2025 12:46:44 +0100
parents 804a823c63f5
children fc1055878775
comparison
equal deleted inserted replaced
172:804a823c63f5 173:e081b6ee5570
339 dir_digests = {} 339 dir_digests = {}
340 340
341 if not handle_root_logical and os.path.islink(root): 341 if not handle_root_logical and os.path.islink(root):
342 linktgt = util.fsencode(os.readlink(root)) 342 linktgt = util.fsencode(os.readlink(root))
343 linkdgst = algorithm[0]() 343 linkdgst = algorithm[0]()
344 linkdgst.update(b"%d:%s," % (len(linktgt), linktgt)) 344 linkdgst.update(
345 util.interpolate_bytes(b"%d:%s,", len(linktgt), linktgt))
345 dir_dgst = algorithm[0]() 346 dir_dgst = algorithm[0]()
346 dir_dgst.update(b"1:L,") 347 dir_dgst.update(b"1:L,")
347 dir_dgst.update( 348 dir_dgst.update(
348 b"%d:%s," % (len(linkdgst.digest()), linkdgst.digest())) 349 util.interpolate_bytes(
350 b"%d:%s,", len(linkdgst.digest()), linkdgst.digest()))
349 if size_only: 351 if size_only:
350 outfp.write( 352 outfp.write(
351 format_bsd_line( 353 format_bsd_line(
352 "SIZE", 354 "SIZE",
353 None, 355 None,
373 for fso in fsobjects: 375 for fso in fsobjects:
374 if fso.is_dir: 376 if fso.is_dir:
375 if fso.is_symlink and not follow_directory_symlinks: 377 if fso.is_symlink and not follow_directory_symlinks:
376 linktgt = util.fsencode(os.readlink(fso.path)) 378 linktgt = util.fsencode(os.readlink(fso.path))
377 linkdgst = algorithm[0]() 379 linkdgst = algorithm[0]()
378 linkdgst.update(b"%d:%s," % (len(linktgt), linktgt)) 380 linkdgst.update(
379 dir_dgst.update(b"1:S,%d:%s," 381 util.interpolate_bytes(
380 % (len(fso.fsname), fso.fsname)) 382 b"%d:%s,", len(linktgt), linktgt))
383 dir_dgst.update(util.interpolate_bytes(
384 b"1:S,%d:%s,", len(fso.fsname), fso.fsname))
381 # no mtime and no mode for symlinks 385 # no mtime and no mode for symlinks
382 dir_dgst.update( 386 dir_dgst.update(util.interpolate_bytes(
383 b"%d:%s," 387 b"%d:%s,",
384 % (len(linkdgst.digest()), linkdgst.digest())) 388 len(linkdgst.digest()), linkdgst.digest()))
385 opath = "/".join(top) + "/" + fso.name if top else fso.name 389 opath = "/".join(top) + "/" + fso.name if top else fso.name
386 if size_only: 390 if size_only:
387 outfp.write( 391 outfp.write(
388 format_bsd_line( 392 format_bsd_line(
389 "SIZE", 393 "SIZE",
401 outfp.flush() 405 outfp.flush()
402 continue 406 continue
403 # fetch from dir_digests 407 # fetch from dir_digests
404 dgst, dsz = dir_digests[top + (fso.name,)] 408 dgst, dsz = dir_digests[top + (fso.name,)]
405 dir_size += dsz 409 dir_size += dsz
406 dir_dgst.update(b"1:d,%d:%s," % (len(fso.fsname), fso.fsname)) 410 dir_dgst.update(util.interpolate_bytes(
407 dir_dgst.update(b"%d:%s," % (len(dgst), dgst)) 411 b"1:d,%d:%s,", len(fso.fsname), fso.fsname))
412 dir_dgst.update(util.interpolate_bytes(
413 b"%d:%s,", len(dgst), dgst))
408 if with_metadata_full_mode: 414 if with_metadata_full_mode:
409 modestr = normalized_mode_str(fso.stat.st_mode) 415 modestr = normalized_mode_str(fso.stat.st_mode)
410 if not isinstance(modestr, bytes): 416 if not isinstance(modestr, bytes):
411 modestr = modestr.encode("ascii") 417 modestr = modestr.encode("ascii")
412 dir_dgst.update(b"8:fullmode,%d:%s," 418 dir_dgst.update(util.interpolate_bytes(
413 % (len(modestr), modestr)) 419 b"8:fullmode,%d:%s,", len(modestr), modestr))
414 elif with_metadata_mode: 420 elif with_metadata_mode:
415 modestr = normalized_compatible_mode_str(fso.stat.st_mode) 421 modestr = normalized_compatible_mode_str(fso.stat.st_mode)
416 if not isinstance(modestr, bytes): 422 if not isinstance(modestr, bytes):
417 modestr = modestr.encode("ascii") 423 modestr = modestr.encode("ascii")
418 dir_dgst.update(b"4:mode,%d:%s," % (len(modestr), modestr)) 424 dir_dgst.update(util.interpolate_bytes(
425 b"4:mode,%d:%s,", len(modestr), modestr))
419 else: 426 else:
420 dir_dgst.update(b"1:f,%d:%s," % (len(fso.fsname), fso.fsname)) 427 dir_dgst.update(util.interpolate_bytes(
428 b"1:f,%d:%s,", len(fso.fsname), fso.fsname))
421 dir_size += fso.stat.st_size 429 dir_size += fso.stat.st_size
422 if with_metadata_mtime: 430 if with_metadata_mtime:
423 mtime = datetime.datetime.utcfromtimestamp( 431 mtime = datetime.datetime.utcfromtimestamp(
424 int(fso.stat.st_mtime)) 432 int(fso.stat.st_mtime))
425 mtime = mtime.isoformat("T") + "Z" 433 mtime = mtime.isoformat("T") + "Z"
426 if not isinstance(mtime, bytes): 434 if not isinstance(mtime, bytes):
427 mtime = mtime.encode("ascii") 435 mtime = mtime.encode("ascii")
428 dir_dgst.update(b"5:mtime,%d:%s," % (len(mtime), mtime)) 436 dir_dgst.update(util.interpolate_bytes(
437 b"5:mtime,%d:%s,", len(mtime), mtime))
429 if with_metadata_full_mode: 438 if with_metadata_full_mode:
430 modestr = normalized_mode_str(fso.stat.st_mode) 439 modestr = normalized_mode_str(fso.stat.st_mode)
431 if not isinstance(modestr, bytes): 440 if not isinstance(modestr, bytes):
432 modestr = modestr.encode("ascii") 441 modestr = modestr.encode("ascii")
433 dir_dgst.update(b"8:fullmode,%d:%s," 442 dir_dgst.update(util.interpolate_bytes(
434 % (len(modestr), modestr)) 443 b"8:fullmode,%d:%s,", len(modestr), modestr))
435 elif with_metadata_mode: 444 elif with_metadata_mode:
436 modestr = normalized_compatible_mode_str(fso.stat.st_mode) 445 modestr = normalized_compatible_mode_str(fso.stat.st_mode)
437 if not isinstance(modestr, bytes): 446 if not isinstance(modestr, bytes):
438 modestr = modestr.encode("ascii") 447 modestr = modestr.encode("ascii")
439 dir_dgst.update(b"4:mode,%d:%s," % (len(modestr), modestr)) 448 dir_dgst.update(util.interpolate_bytes(
449 b"4:mode,%d:%s,", len(modestr), modestr))
440 if not size_only: 450 if not size_only:
441 dgst = digest.compute_digest_file( 451 dgst = digest.compute_digest_file(
442 algorithm[0], fso.path, use_mmap=use_mmap) 452 algorithm[0], fso.path, use_mmap=use_mmap)
443 dir_dgst.update(b"%d:%s," % (len(dgst), dgst)) 453 dir_dgst.update(util.interpolate_bytes(
454 b"%d:%s,", len(dgst), dgst))
444 opath = "/".join(top) + "/" + fso.name if top else fso.name 455 opath = "/".join(top) + "/" + fso.name if top else fso.name
445 if size_only: 456 if size_only:
446 outfp.write( 457 outfp.write(
447 format_bsd_line( 458 format_bsd_line(
448 "SIZE", None, opath, False, fso.stat.st_size)) 459 "SIZE", None, opath, False, fso.stat.st_size))
494 else os.linesep.encode("utf-8") 505 else os.linesep.encode("utf-8")
495 if not isinstance(what, bytes): 506 if not isinstance(what, bytes):
496 what = what.encode("ascii") 507 what = what.encode("ascii")
497 if what == b"TIMESTAMP": 508 if what == b"TIMESTAMP":
498 assert filename is None 509 assert filename is None
499 return b"TIMESTAMP = %d%s" % (value, ls) 510 return util.interpolate_bytes(b"TIMESTAMP = %d%s", value, ls)
500 if what in (b"ISOTIMESTAMP", b"FLAGS", b"VERSION"): 511 if what in (b"ISOTIMESTAMP", b"FLAGS", b"VERSION"):
501 assert filename is None 512 assert filename is None
502 if not isinstance(value, bytes): 513 if not isinstance(value, bytes):
503 value = value.encode("ascii") 514 value = value.encode("ascii")
504 return b"%s = %s%s" % (what, value, ls) 515 return util.interpolate_bytes(b"%s = %s%s", what, value, ls)
505 assert filename is not None 516 assert filename is not None
506 if what == b"COMMENT": 517 if what == b"COMMENT":
507 if not isinstance(filename, bytes): 518 if not isinstance(filename, bytes):
508 filename = filename.encode("utf-8") 519 filename = filename.encode("utf-8")
509 return b"COMMENT (%s)%s" % (filename, ls) 520 return util.interpolate_bytes(b"COMMENT (%s)%s", filename, ls)
510 if not isinstance(filename, bytes): 521 if not isinstance(filename, bytes):
511 filename = util.fsencode(filename) 522 filename = util.fsencode(filename)
512 if what == b"SIZE": 523 if what == b"SIZE":
513 return b"SIZE (%s) = %d%s" % (filename, size, ls) 524 return util.interpolate_bytes(b"SIZE (%s) = %d%s", filename, size, ls)
514 if value is None: 525 if value is None:
515 return b"%s (%s)%s" % (what, filename, ls) 526 return util.interpolate_bytes(b"%s (%s)%s", what, filename, ls)
516 if use_base64: 527 if use_base64:
517 value = base64.b64encode(value) 528 value = base64.b64encode(value)
518 else: 529 else:
519 value = binascii.hexlify(value) 530 value = binascii.hexlify(value)
520 if filename != b"./@": 531 if filename != b"./@":
521 filename = util.normalize_filename(filename, True) 532 filename = util.normalize_filename(filename, True)
522 if size is None: 533 if size is None:
523 return b"%s (%s) = %s%s" % (what, filename, value, ls) 534 return util.interpolate_bytes(
535 b"%s (%s) = %s%s", what, filename, value, ls)
524 else: 536 else:
525 return b"%s (%s) = %s,%d%s" % (what, filename, value, size, ls) 537 return util.interpolate_bytes(
538 b"%s (%s) = %s,%d%s", what, filename, value, size, ls)
526 539
527 540
528 if __name__ == "__main__": 541 if __name__ == "__main__":
529 sys.exit(main()) 542 sys.exit(main())