1+ import logging
12import os
23import pathlib
34import subprocess
45import typing
56from unittest import mock
67
78import pytest
9+ from packaging .requirements import Requirement
10+ from packaging .version import Version
811
9- from fromager import external_commands
12+ from fromager import external_commands , log
1013
1114
1215def test_external_commands_environ () -> None :
@@ -29,7 +32,10 @@ def test_external_commands_log_file(tmp_path: pathlib.Path) -> None:
2932 assert "test\n " == file_contents
3033
3134
32- @mock .patch ("subprocess.run" , return_value = mock .Mock (returncode = 0 ))
35+ @mock .patch (
36+ "subprocess.run" ,
37+ return_value = mock .Mock (returncode = 0 , stdout = b"test output\n " ),
38+ )
3339@mock .patch (
3440 "fromager.external_commands.network_isolation_cmd" ,
3541 return_value = ["/bin/unshare" , "--net" , "--map-current-user" ],
@@ -85,3 +91,43 @@ def test_external_commands_network_isolation_real() -> None:
8591 )
8692 exc = typing .cast (subprocess .CalledProcessError , e .value )
8793 assert exc .returncode == 1
94+
95+
96+ def test_external_command_output_prefix (caplog : pytest .LogCaptureFixture ) -> None :
97+ """Test that external command output is prefixed with package name on each line."""
98+ # Set up the log record factory to enable automatic prefixing
99+ old_factory = logging .getLogRecordFactory ()
100+ logging .setLogRecordFactory (log .FromagerLogRecord )
101+
102+ try :
103+ req = Requirement ("test-package==1.0.0" )
104+ version = Version ("1.0.0" )
105+
106+ with log .req_ctxvar_context (req , version ):
107+ with caplog .at_level (logging .DEBUG , logger = "fromager.external_commands" ):
108+ # Run a command that produces multi-line output
109+ # Use printf for cross-platform compatibility (echo -e doesn't work on macOS)
110+ external_commands .run (["printf" , "line1\\ nline2\\ nline3" ])
111+
112+ # Get the last debug log record (the output message)
113+ output_rec = caplog .records [- 1 ]
114+ message = output_rec .getMessage ()
115+
116+ # Verify that each line has the package name prefix
117+ # The first line gets the prefix from FromagerLogRecord.getMessage()
118+ # Continuation lines get it from external_commands.run()
119+ expected_prefix = "test-package-1.0.0: "
120+ assert message .startswith (expected_prefix ), (
121+ f"Message should start with '{ expected_prefix } '"
122+ )
123+
124+ # Check that all lines have the prefix
125+ lines = message .split ("\n " )
126+ for line in lines :
127+ if line : # Skip empty lines
128+ assert line .startswith (expected_prefix ), (
129+ f"Line '{ line } ' should start with '{ expected_prefix } '"
130+ )
131+ finally :
132+ # Restore the original log record factory
133+ logging .setLogRecordFactory (old_factory )
0 commit comments