comparison cutils/treesum.py @ 367:8a8a43e8369d

treesum: FIX: Handle line endings on Windows with redirected stdout properly
author Franz Glasner <fzglas.hg@dom66.de>
date Thu, 10 Apr 2025 01:54:09 +0200
parents 5fffacc390eb
children bfe1160fbfd3
comparison
equal deleted inserted replaced
366:5fffacc390eb 367:8a8a43e8369d
564 if opts.output is None or opts.output == "-": 564 if opts.output is None or opts.output == "-":
565 if hasattr(sys.stdout, "buffer"): 565 if hasattr(sys.stdout, "buffer"):
566 out_cm = cm.nullcontext(sys.stdout.buffer) 566 out_cm = cm.nullcontext(sys.stdout.buffer)
567 else: 567 else:
568 out_cm = cm.nullcontext(sys.stdout) 568 out_cm = cm.nullcontext(sys.stdout)
569 is_stdout = True
569 else: 570 else:
570 if opts.append_output: 571 if opts.append_output:
571 out_cm = open(opts.output, "ab") 572 out_cm = open(opts.output, "ab")
572 else: 573 else:
573 out_cm = open(opts.output, "wb") 574 out_cm = open(opts.output, "wb")
575 is_stdout = False
574 576
575 fnmatcher = fnmatch.FnMatcher.build_from_commandline_patterns( 577 fnmatcher = fnmatch.FnMatcher.build_from_commandline_patterns(
576 opts.fnmatch_filters) 578 opts.fnmatch_filters)
577 579
578 if opts.output_style in ("tagged", "tag"): 580 if opts.output_style in ("tagged", "tag"):
582 else: 584 else:
583 raise NotImplementedError("`output_style'") 585 raise NotImplementedError("`output_style'")
584 586
585 with out_cm as outfp: 587 with out_cm as outfp:
586 writer = writerstyle(outfp, 588 writer = writerstyle(outfp,
589 is_stdout=is_stdout,
587 size_only=opts.size_only, 590 size_only=opts.size_only,
588 print_size=opts.print_size, 591 print_size=opts.print_size,
589 use_base64=opts.base64, 592 use_base64=opts.base64,
590 grouping_separator=opts.grouping_separator, 593 grouping_separator=opts.grouping_separator,
591 size_column_width=opts.size_column_width, 594 size_column_width=opts.size_column_width,
1326 separator for your OS as bytes""" 1329 separator for your OS as bytes"""
1327 1330
1328 DEFAULT_GROUPING_SEPARATOR = "" 1331 DEFAULT_GROUPING_SEPARATOR = ""
1329 """Disable the thousands separator in case no subclass redefines it""" 1332 """Disable the thousands separator in case no subclass redefines it"""
1330 1333
1331 def __init__(self, outfp, size_only=False, print_size=False, 1334 def __init__(self, outfp, is_stdout=False,
1335 size_only=False, print_size=False,
1332 use_base64=False, grouping_separator=None, 1336 use_base64=False, grouping_separator=None,
1333 size_column_width=None): 1337 size_column_width=None):
1334 # Poor man's abstract abstract class implemenetation 1338 # Poor man's abstract abstract class implemenetation
1335 assert self.__class__ is not WriterBase 1339 assert self.__class__ is not WriterBase
1336 1340
1337 self._outfp = outfp 1341 self._outfp = outfp
1342 try:
1343 self._outfp_is_tty = self._outfp.isatty()
1344 except: # noqa: E722 bare except
1345 self._outfp_is_tty = None
1346 self._is_windows = sys.platform == "win32"
1347 self._is_stdout = is_stdout
1338 self.size_only = size_only 1348 self.size_only = size_only
1339 self.print_size = print_size 1349 self.print_size = print_size
1340 self.use_base64 = use_base64 1350 self.use_base64 = use_base64
1341 self.grouping_separator = (grouping_separator 1351 self.grouping_separator = (grouping_separator
1342 if grouping_separator is not None 1352 if grouping_separator is not None
1383 1393
1384 :param bytes line: The line to write to (without line ending) 1394 :param bytes line: The line to write to (without line ending)
1385 1395
1386 """ 1396 """
1387 self.write(line) 1397 self.write(line)
1388 self.write(self.LS) 1398 if self._is_windows:
1399 if self._is_stdout:
1400 if self._outfp_is_tty:
1401 # Windows handles this correctly in its terminal
1402 self.write(self.LS)
1403 else:
1404 #
1405 # Simulate a CR-LF for the CRC but write a LF only.
1406 # This will be converted to a CR-LF on Windows by
1407 # the runtime libs.
1408 #
1409 self._crc.update(b'\r')
1410 self.write(b'\n')
1411 else:
1412 self.write(self.LS)
1413 else:
1414 self.write(self.LS)
1389 1415
1390 def write(self, data): 1416 def write(self, data):
1391 """Write `data` into the output file and update the CRC accordingly. 1417 """Write `data` into the output file and update the CRC accordingly.
1392 1418
1393 :param bytes data: The data to write to and to update the CRC with 1419 :param bytes data: The data to write to and to update the CRC with