comparison cutils/treesum.py @ 341:728ad9c639f2

treesum: right-align the output of size when using the tabular style
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 31 Mar 2025 15:24:48 +0200
parents cfa544fbb9f9
children 0a58948df713
comparison
equal deleted inserted replaced
340:cfa544fbb9f9 341:728ad9c639f2
561 with out_cm as outfp: 561 with out_cm as outfp:
562 writer = writerstyle(outfp, 562 writer = writerstyle(outfp,
563 size_only=opts.size_only, 563 size_only=opts.size_only,
564 print_size=opts.print_size, 564 print_size=opts.print_size,
565 use_base64=opts.base64, 565 use_base64=opts.base64,
566 grouping_separator=opts.grouping_separator 566 grouping_separator=opts.grouping_separator,
567 size_column_width=opts.size_column_width,
567 ) 568 )
568 for d in opts.directories: 569 for d in opts.directories:
569 V1DirectoryTreesumGenerator( 570 V1DirectoryTreesumGenerator(
570 opts.algorithm, opts.mmap, 571 opts.algorithm, opts.mmap,
571 opts.follow_symlinks, 572 opts.follow_symlinks,
1488 self.writeln(b")") 1489 self.writeln(b")")
1489 1490
1490 def write_file_digest(self, algorithm, filename, digest, size): 1491 def write_file_digest(self, algorithm, filename, digest, size):
1491 assert isinstance(filename, bytes) 1492 assert isinstance(filename, bytes)
1492 if digest is not None: 1493 if digest is not None:
1493 digest = (base64.b64encode(digest) 1494 if digest != b"":
1494 if self.use_base64 1495 digest = (base64.b64encode(digest)
1495 else binascii.hexlify(digest)) 1496 if self.use_base64
1497 else binascii.hexlify(digest))
1496 self.write(util.b(algorithm)) 1498 self.write(util.b(algorithm))
1497 self.write(b" (") 1499 self.write(b" (")
1498 self.write(filename) 1500 self.write(filename)
1499 self.write(b")") 1501 self.write(b")")
1500 if digest is not None or size is not None: 1502 if digest is not None or size is not None:
1529 DEFAULT_GROUPING_SEPARATOR = '.' 1531 DEFAULT_GROUPING_SEPARATOR = '.'
1530 """The default thousands separator""" 1532 """The default thousands separator"""
1531 1533
1532 def __init__(self, outfp, **kwds): 1534 def __init__(self, outfp, **kwds):
1533 super(TabularTreesumWriter, self).__init__(outfp, **kwds) 1535 super(TabularTreesumWriter, self).__init__(outfp, **kwds)
1536 # Prepare some format strings for performance reasons
1537 if self.size_column_width > 0:
1538 self._formatstring_size = '>' + str(self.size_column_width)
1539 self._errorstring_size = b'?' * self.size_column_width
1540 self._emptystring_size = b' ' * self.size_column_width
1541 else:
1542 self._formatstring_size = ">"
1543 self._errorstring_size = b"?????"
1544 self._emptystring_size = b''
1545 if self.grouping_separator:
1546 self._formatstring_size += ','
1547 self._formatstring_size += 'd'
1534 1548
1535 def start(self, version): 1549 def start(self, version):
1536 """Begin a new block, reset the current CRC and write the VERSION 1550 """Begin a new block, reset the current CRC and write the VERSION
1537 tag. 1551 tag.
1538 1552
1588 1602
1589 def write_size(self, filename, sz): 1603 def write_size(self, filename, sz):
1590 assert isinstance(filename, bytes) 1604 assert isinstance(filename, bytes)
1591 if sz is not None: 1605 if sz is not None:
1592 if sz >= 0: 1606 if sz >= 0:
1593 self.write(util.b(format(sz, ',').replace( 1607 self.write(util.b(format(
1594 ',', self.grouping_separator))) 1608 sz, self._formatstring_size).replace(
1609 ',', self.grouping_separator)))
1595 else: 1610 else:
1596 self.write(b"?????") 1611 self.write(self._emptystring_size)
1612 else:
1613 self.write(self._errorstring_size)
1597 self.write(b"\t") 1614 self.write(b"\t")
1598 self.writeln(filename) 1615 self.writeln(filename)
1599 1616
1600 def write_accept_treesum_file(self, filename): 1617 def write_accept_treesum_file(self, filename):
1601 assert isinstance(filename, bytes) 1618 assert isinstance(filename, bytes)
1602 self.write(b"ACCEPT-TREESUM\t") 1619 self.write(b"ACCEPT-TREESUM\t")
1603 self.writeln(filename) 1620 self.writeln(filename)
1604 1621
1605 def write_file_digest(self, algorithm, filename, digest, size): 1622 def write_file_digest(self, algorithm, filename, digest, size):
1606 assert isinstance(filename, bytes) 1623 assert isinstance(filename, bytes)
1607 if digest is not None: 1624 if digest is not None and digest != b"":
1608 digest = (base64.b64encode(digest) 1625 digest = (base64.b64encode(digest) if self.use_base64
1609 if self.use_base64
1610 else binascii.hexlify(digest)) 1626 else binascii.hexlify(digest))
1627 else:
1628 #
1629 # Compute an error digest string with the "correct" length for
1630 # given algorithm
1631 #
1632 nulldigest = b'\0' * util.algotag2digest_size(algorithm)
1633 dsz = len(base64.b64encode(nulldigest) if self.use_base64
1634 else binascii.hexlify(nulldigest))
1635 if digest is None:
1636 digest = b'?' * dsz
1637 else:
1638 digest = b' ' * dsz
1611 self.write(util.b(algorithm)) 1639 self.write(util.b(algorithm))
1612 self.write(b":") 1640 self.write(b":")
1613 if digest is not None: 1641 self.write(digest)
1614 self.write(digest)
1615 else:
1616 self.write(b"?????")
1617 self.write(b"\t") 1642 self.write(b"\t")
1618 if size is not None: 1643 if self.print_size:
1619 if size >= 0: 1644 if size is not None:
1620 self.write(util.b(format(size, ',').replace( 1645 if size >= 0:
1621 ',', self.grouping_separator))) 1646 self.write(util.b(format(
1647 size, self._formatstring_size).replace(
1648 ',', self.grouping_separator)))
1649 else:
1650 self.write(self._emptystring_size)
1622 else: 1651 else:
1623 self.write(b"?????") 1652 self.write(self._errorstring_size)
1624 self.write(b"\t") 1653 self.write(b"\t")
1625 self.writeln(filename) 1654 self.writeln(filename)
1626 1655
1627 def finish(self): 1656 def finish(self):
1628 """Finish a block and write the current CRC""" 1657 """Finish a block and write the current CRC"""