Mercurial > hgrepos > Python > apps > py-cutils
comparison cutils/treesum.py @ 330:61cbae10103c
treesum: first minimal version of writing the treesum output in tabular format.
BUGS: Reading tabular output is not yet supported.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Fri, 28 Mar 2025 14:20:45 +0100 |
| parents | e2ae72792f56 |
| children | 9ee84624587f |
comparison
equal
deleted
inserted
replaced
| 329:e2ae72792f56 | 330:61cbae10103c |
|---|---|
| 165 "--output", "-o", action="store", metavar="OUTPUT", | 165 "--output", "-o", action="store", metavar="OUTPUT", |
| 166 help="Put the checksum into given file. " | 166 help="Put the checksum into given file. " |
| 167 "If not given or if it is given as `-' then stdout is used.") | 167 "If not given or if it is given as `-' then stdout is used.") |
| 168 gp.add_argument( | 168 gp.add_argument( |
| 169 "--output-style", dest="output_style", default="tagged", | 169 "--output-style", dest="output_style", default="tagged", |
| 170 choices=("tagged", "tag"), | 170 choices=("tagged", "tag", "tabular", "tab"), |
| 171 help=""" | 171 help=""" |
| 172 Select the output style: "tagged" or "tag" selects BSD style tagged format. | 172 Select the output style: "tagged" or "tag" selects a more BSD style tagged |
| 173 format. "tabular" or "tab" select a more GNU style tabular format. | |
| 173 Default is "tagged". | 174 Default is "tagged". |
| 174 """) | 175 """) |
| 175 gp.add_argument( | 176 gp.add_argument( |
| 176 "--physical", "-P", action=SymlinkAction, dest="follow_symlinks", | 177 "--physical", "-P", action=SymlinkAction, dest="follow_symlinks", |
| 177 const=FollowSymlinkConfig(False, False, False), | 178 const=FollowSymlinkConfig(False, False, False), |
| 454 "every kind of every item in `fnmatch_filters' must be" | 455 "every kind of every item in `fnmatch_filters' must be" |
| 455 " \"include\", \"exclude\" or \"accept-treesum\"" | 456 " \"include\", \"exclude\" or \"accept-treesum\"" |
| 456 ) | 457 ) |
| 457 if generator not in ("normal", "full", "none"): | 458 if generator not in ("normal", "full", "none"): |
| 458 raise ValueError("given generator `%s' not allowed" % (generator, )) | 459 raise ValueError("given generator `%s' not allowed" % (generator, )) |
| 459 if output_style not in ("tagged", "tag"): | 460 if output_style not in ("tagged", "tag", "tabular", "tab"): |
| 460 raise ValueError( | 461 raise ValueError( |
| 461 "given output_style `%s' not allowed" % (output_style,)) | 462 "given output_style `%s' not allowed" % (output_style,)) |
| 462 | 463 |
| 463 # Not following symlinks to files is not yet supported: reset to True | 464 # Not following symlinks to files is not yet supported: reset to True |
| 464 # if not follow_symlinks.file: | 465 # if not follow_symlinks.file: |
| 528 out_cm = open(opts.output, "wb") | 529 out_cm = open(opts.output, "wb") |
| 529 | 530 |
| 530 fnmatcher = fnmatch.FnMatcher.build_from_commandline_patterns( | 531 fnmatcher = fnmatch.FnMatcher.build_from_commandline_patterns( |
| 531 opts.fnmatch_filters) | 532 opts.fnmatch_filters) |
| 532 | 533 |
| 533 assert opts.output_style in ("tagged", "tag") | 534 if opts.output_style in ("tagged", "tag"): |
| 535 writerstyle = TaggedTreesumWriter | |
| 536 elif opts.output_style in ("tabular", "tab"): | |
| 537 writerstyle = TabularTreesumWriter | |
| 538 else: | |
| 539 raise NotImplementedError("`output_style'") | |
| 534 | 540 |
| 535 with out_cm as outfp: | 541 with out_cm as outfp: |
| 536 writer = TaggedTreesumWriter(outfp) | 542 writer = writerstyle(outfp) |
| 537 for d in opts.directories: | 543 for d in opts.directories: |
| 538 V1DirectoryTreesumGenerator( | 544 V1DirectoryTreesumGenerator( |
| 539 opts.algorithm, opts.mmap, opts.base64, | 545 opts.algorithm, opts.mmap, opts.base64, |
| 540 opts.follow_symlinks, | 546 opts.follow_symlinks, |
| 541 opts.generator, | 547 opts.generator, |
| 1439 self.write(b"CRC32 = ") | 1445 self.write(b"CRC32 = ") |
| 1440 self.writeln(util.b(crc)) | 1446 self.writeln(util.b(crc)) |
| 1441 self.flush() | 1447 self.flush() |
| 1442 | 1448 |
| 1443 | 1449 |
| 1450 class TabularTreesumWriter(WriterBase): | |
| 1451 | |
| 1452 """Writer to write treesum digest files in a format similar to tabular | |
| 1453 GNU digest files. | |
| 1454 | |
| 1455 Provides high-level methods to write data lines. | |
| 1456 | |
| 1457 """ | |
| 1458 | |
| 1459 def __init__(self, outfp, **kwds): | |
| 1460 super(TabularTreesumWriter, self).__init__(outfp) | |
| 1461 | |
| 1462 def start(self, version): | |
| 1463 """Begin a new block, reset the current CRC and write the VERSION | |
| 1464 tag. | |
| 1465 | |
| 1466 """ | |
| 1467 self.reset_crc() | |
| 1468 self.write(b"VERSION\t") | |
| 1469 self.writeln(util.b(version)) | |
| 1470 | |
| 1471 def write_comment(self, comment): | |
| 1472 self.write(b"COMMENT\t") | |
| 1473 self.writeln(util.b(comment, "utf-8")) | |
| 1474 | |
| 1475 def write_generator(self, generator): | |
| 1476 self.write(b"GENERATOR\t") | |
| 1477 self.writeln(util.b(generator, "utf-8")) | |
| 1478 | |
| 1479 def write_error(self, error): | |
| 1480 self.write(b"ERROR\t") | |
| 1481 self.writeln(util.b(error, "utf-8")) | |
| 1482 | |
| 1483 def write_fsencoding(self, encoding): | |
| 1484 self.write(b"FSENCODING\t") | |
| 1485 self.writeln(util.b(encoding)) | |
| 1486 | |
| 1487 def write_fnmatch_pattern(self, action, kind, pattern): | |
| 1488 self.write(b"FNMATCH\t") | |
| 1489 self.write(util.b(action)) | |
| 1490 self.write(b": ") | |
| 1491 self.write(util.b(kind)) | |
| 1492 self.write(b":") | |
| 1493 self.writeln(util.b(pattern, "utf-8")) | |
| 1494 | |
| 1495 def write_flags(self, flags): | |
| 1496 self.write(b"FLAGS\t") | |
| 1497 if isinstance(flags, (str, bytes)): | |
| 1498 self.writeln(util.b(flags)) | |
| 1499 else: | |
| 1500 flags.sort() | |
| 1501 self.writeln(util.b(",".join(flags))) | |
| 1502 | |
| 1503 def write_timestamp(self, ts): | |
| 1504 self.write(b"TIMESTAMP\t") | |
| 1505 self.writeln(util.b(str(ts))) | |
| 1506 | |
| 1507 def write_isotimestamp(self, ts): | |
| 1508 self.write(b"ISOTIMESTAMP\t") | |
| 1509 self.writeln(util.b(ts)) | |
| 1510 | |
| 1511 def write_root(self, root): | |
| 1512 assert isinstance(root, bytes) | |
| 1513 self.write(b"ROOT\t") | |
| 1514 self.writeln(root) | |
| 1515 | |
| 1516 def write_size(self, filename, sz): | |
| 1517 assert isinstance(filename, bytes) | |
| 1518 if sz is not None: | |
| 1519 self.write(util.b(str(sz))) | |
| 1520 self.write(b"\t") | |
| 1521 self.writeln(filename) | |
| 1522 | |
| 1523 def write_accept_treesum_file(self, filename): | |
| 1524 assert isinstance(filename, bytes) | |
| 1525 self.write(b"ACCEPT-TREESUM\t") | |
| 1526 self.writeln(filename) | |
| 1527 | |
| 1528 def write_file_digest(self, algorithm, filename, digest, | |
| 1529 use_base64=False, size=None): | |
| 1530 assert isinstance(filename, bytes) | |
| 1531 if digest is not None: | |
| 1532 digest = (base64.b64encode(digest) | |
| 1533 if use_base64 | |
| 1534 else binascii.hexlify(digest)) | |
| 1535 self.write(util.b(algorithm)) | |
| 1536 self.write(b":") | |
| 1537 if digest is not None: | |
| 1538 self.write(digest) | |
| 1539 self.write(b"\t") | |
| 1540 if size is not None: | |
| 1541 self.write(util.b(str(size))) | |
| 1542 self.write(b"\t") | |
| 1543 self.writeln(filename) | |
| 1544 | |
| 1545 def finish(self): | |
| 1546 """Finish a block and write the current CRC""" | |
| 1547 crc = self.crc.hexdigest() | |
| 1548 self.write(b"CRC32\t") | |
| 1549 self.writeln(util.b(crc)) | |
| 1550 self.flush() | |
| 1551 | |
| 1552 | |
| 1444 class TreesumReader(object): | 1553 class TreesumReader(object): |
| 1445 | 1554 |
| 1446 """Reader to read and/or verify treesum digest files. | 1555 """Reader to read and/or verify treesum digest files. |
| 1447 | 1556 |
| 1448 Supports the iterator and context manager protocol. | 1557 Supports the iterator and context manager protocol. |
