Skip to content

Commit a7137da

Browse files
committed
git.cmd.Git.execute(..): fix with_stdout=False
In the event the end-user called one of the APIs with `with_stdout=False`, i.e., they didn't want to capture stdout, the code would crash with an AttributeError or ValueError when trying to dereference the stdout/stderr streams attached to `Popen(..)` objects. Be more defensive by checking the streams first to make sure they're not `None` before trying to access their corresponding attributes. Add myself to AUTHORS and add corresponding regression tests for the change. Signed-off-by: Enji Cooper <yaneurabeya@gmail.com>
1 parent 28c34c5 commit a7137da

File tree

3 files changed

+34
-8
lines changed

3 files changed

+34
-8
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@ Contributors are:
5656
-Ethan Lin <et.repositories _at_ gmail.com>
5757
-Jonas Scharpf <jonas.scharpf _at_ checkmk.com>
5858
-Gordon Marx
59+
-Enji Cooper
5960

6061
Portions derived from other open source works and are clearly marked.

git/cmd.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,25 +1364,30 @@ def communicate() -> Tuple[AnyStr, AnyStr]:
13641364
if output_stream is None:
13651365
stdout_value, stderr_value = communicate()
13661366
# Strip trailing "\n".
1367-
if stdout_value.endswith(newline) and strip_newline_in_stdout: # type: ignore[arg-type]
1367+
if (stdout_value is not None and stdout_value.endswith(newline) and
1368+
strip_newline_in_stdout): # type: ignore[arg-type]
13681369
stdout_value = stdout_value[:-1]
1369-
if stderr_value.endswith(newline): # type: ignore[arg-type]
1370+
if stderr_value is not None and stderr_value.endswith(newline): # type: ignore[arg-type]
13701371
stderr_value = stderr_value[:-1]
13711372

13721373
status = proc.returncode
13731374
else:
13741375
max_chunk_size = max_chunk_size if max_chunk_size and max_chunk_size > 0 else io.DEFAULT_BUFFER_SIZE
1375-
stream_copy(proc.stdout, output_stream, max_chunk_size)
1376-
stdout_value = proc.stdout.read()
1377-
stderr_value = proc.stderr.read()
1376+
if proc.stdout is not None:
1377+
stream_copy(proc.stdout, output_stream, max_chunk_size)
1378+
stdout_value = proc.stdout.read()
1379+
if proc.stderr is not None:
1380+
stderr_value = proc.stderr.read()
13781381
# Strip trailing "\n".
1379-
if stderr_value.endswith(newline): # type: ignore[arg-type]
1382+
if stderr_value is not None and stderr_value.endswith(newline): # type: ignore[arg-type]
13801383
stderr_value = stderr_value[:-1]
13811384
status = proc.wait()
13821385
# END stdout handling
13831386
finally:
1384-
proc.stdout.close()
1385-
proc.stderr.close()
1387+
if proc.stdout is not None:
1388+
proc.stdout.close()
1389+
if proc.stderr is not None:
1390+
proc.stderr.close()
13861391

13871392
if self.GIT_PYTHON_TRACE == "full":
13881393
cmdstr = " ".join(redacted_command)

test/test_git.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import contextlib
77
import gc
88
import inspect
9+
import io
910
import logging
1011
import os
1112
import os.path as osp
@@ -201,6 +202,25 @@ def test_it_logs_istream_summary_for_stdin(self, case):
201202
def test_it_executes_git_and_returns_result(self):
202203
self.assertRegex(self.git.execute(["git", "version"]), r"^git version [\d\.]{2}.*$")
203204

205+
def test_it_output_stream_with_stdout_is_false(self):
206+
temp_stream = io.BytesIO()
207+
self.git.execute(
208+
["git", "version"],
209+
output_stream=temp_stream,
210+
with_stdout=False,
211+
)
212+
self.assertEqual(temp_stream.tell(), 0)
213+
214+
def test_it_executes_git_without_stdout_redirect(self):
215+
returncode, stdout, stderr = self.git.execute(
216+
["git", "version"],
217+
with_extended_output=True,
218+
with_stdout=False,
219+
)
220+
self.assertEqual(returncode, 0)
221+
self.assertIsNone(stdout)
222+
self.assertIsNotNone(stderr)
223+
204224
@ddt.data(
205225
# chdir_to_repo, shell, command, use_shell_impostor
206226
(False, False, ["git", "version"], False),

0 commit comments

Comments
 (0)