WIP: Fix carriage return
This commit is contained in:
@@ -126,9 +126,19 @@ def handle_io(
|
||||
|
||||
# If Log.STDOUT is set, log the stdout output
|
||||
if ret and log in [Log.STDOUT, Log.BOTH]:
|
||||
lines = ret.decode("utf-8", "replace").rstrip("\n").rstrip().split("\n")
|
||||
decoded = ret.decode("utf-8", "replace").rstrip("\n").rstrip()
|
||||
# Handle carriage returns: split by \r and only keep the last segment of each line
|
||||
# This prevents progress indicators that use \r from creating multiple log lines
|
||||
lines = []
|
||||
for line in decoded.split("\n"):
|
||||
if "\r" in line:
|
||||
# Only keep the last segment after the final \r (what would be visible)
|
||||
lines.append(line.split("\r")[-1])
|
||||
else:
|
||||
lines.append(line)
|
||||
for line in lines:
|
||||
cmdlog.info(line, extra=stdout_extra)
|
||||
if line: # Only log non-empty lines
|
||||
cmdlog.info(line, extra=stdout_extra)
|
||||
|
||||
# If stdout file is set, stream the stdout output
|
||||
if ret and stdout:
|
||||
@@ -143,9 +153,19 @@ def handle_io(
|
||||
|
||||
# If Log.STDERR is set, log the stderr output
|
||||
if ret and log in [Log.STDERR, Log.BOTH]:
|
||||
lines = ret.decode("utf-8", "replace").rstrip("\n").rstrip().split("\n")
|
||||
decoded = ret.decode("utf-8", "replace").rstrip("\n").rstrip()
|
||||
# Handle carriage returns: split by \r and only keep the last segment of each line
|
||||
# This prevents progress indicators that use \r from creating multiple log lines
|
||||
lines = []
|
||||
for line in decoded.split("\n"):
|
||||
if "\r" in line:
|
||||
# Only keep the last segment after the final \r (what would be visible)
|
||||
lines.append(line.split("\r")[-1])
|
||||
else:
|
||||
lines.append(line)
|
||||
for line in lines:
|
||||
cmdlog.info(line, extra=stderr_extra)
|
||||
if line: # Only log non-empty lines
|
||||
cmdlog.info(line, extra=stderr_extra)
|
||||
|
||||
# If stderr file is set, stream the stderr output
|
||||
if ret and stderr:
|
||||
|
||||
59
pkgs/clan-cli/clan_lib/cmd/test_carriage_return.py
Normal file
59
pkgs/clan-cli/clan_lib/cmd/test_carriage_return.py
Normal file
@@ -0,0 +1,59 @@
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from clan_lib.cmd import Log, RunOpts, run
|
||||
|
||||
|
||||
def test_carriage_return_handling(caplog: logging.LogRecord) -> None:
|
||||
"""Test that carriage returns are handled properly to avoid duplicate progress lines."""
|
||||
# Set logging to capture INFO level
|
||||
caplog.set_level(logging.INFO)
|
||||
|
||||
# Run a command that simulates mkfs.ext4 progress output with carriage returns
|
||||
result = run(
|
||||
[
|
||||
"bash",
|
||||
"-c",
|
||||
'printf "Progress: 1/5\\rProgress: 2/5\\rProgress: 3/5\\rProgress: 4/5\\rProgress: 5/5\\n"',
|
||||
],
|
||||
RunOpts(log=Log.STDOUT, cwd=Path.cwd()),
|
||||
)
|
||||
|
||||
# Check that the command succeeded
|
||||
assert result.returncode == 0
|
||||
|
||||
# Check that only the final progress line was logged, not all intermediate ones
|
||||
log_messages = [record.message for record in caplog.records]
|
||||
|
||||
# Should only see the final "Progress: 5/5" message, not all the intermediate ones
|
||||
assert "Progress: 5/5" in log_messages
|
||||
# Count how many "Progress:" messages there are - should be only 1
|
||||
progress_messages = [msg for msg in log_messages if "Progress:" in msg]
|
||||
assert len(progress_messages) == 1, f"Expected 1 progress message, got {len(progress_messages)}: {progress_messages}"
|
||||
|
||||
|
||||
def test_carriage_return_multiple_lines(caplog: logging.LogRecord) -> None:
|
||||
"""Test carriage returns on multiple separate lines."""
|
||||
caplog.set_level(logging.INFO)
|
||||
|
||||
# Simulate multiple lines with progress indicators
|
||||
result = run(
|
||||
[
|
||||
"bash",
|
||||
"-c",
|
||||
'printf "Line 1\\nProgress: 10%%\\rProgress: 50%%\\rProgress: 100%%\\nLine 3\\n"',
|
||||
],
|
||||
RunOpts(log=Log.STDOUT, cwd=Path.cwd()),
|
||||
)
|
||||
|
||||
assert result.returncode == 0
|
||||
log_messages = [record.message for record in caplog.records]
|
||||
|
||||
# Should see Line 1, Progress: 100%, and Line 3
|
||||
assert "Line 1" in log_messages
|
||||
assert "Progress: 100%" in log_messages
|
||||
assert "Line 3" in log_messages
|
||||
|
||||
# Should NOT see the intermediate progress messages
|
||||
assert "Progress: 10%" not in log_messages
|
||||
assert "Progress: 50%" not in log_messages
|
||||
Reference in New Issue
Block a user