Skip to content

Commit 376efb0

Browse files
committed
gitpython-developers#648 max_chunk_size can be now set to control output_stream behavior
1 parent ddb828e commit 376efb0

File tree

2 files changed

+34
-13
lines changed

2 files changed

+34
-13
lines changed

git/cmd.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
execute_kwargs = set(('istream', 'with_extended_output',
4848
'with_exceptions', 'as_process', 'stdout_as_string',
4949
'output_stream', 'with_stdout', 'kill_after_timeout',
50-
'universal_newlines', 'shell', 'env'))
50+
'universal_newlines', 'shell', 'env', 'max_chunk_size'))
5151

5252
log = logging.getLogger(__name__)
5353
log.addHandler(logging.NullHandler())
@@ -175,8 +175,6 @@ def __setstate__(self, d):
175175
dict_to_slots_and__excluded_are_none(self, d, excluded=self._excluded_)
176176

177177
# CONFIGURATION
178-
# The size in bytes read from stdout when copying git's output to another stream
179-
max_chunk_size = io.DEFAULT_BUFFER_SIZE
180178

181179
git_exec_name = "git" # default that should work on linux and windows
182180

@@ -598,6 +596,7 @@ def execute(self, command,
598596
universal_newlines=False,
599597
shell=None,
600598
env=None,
599+
max_chunk_size=io.DEFAULT_BUFFER_SIZE,
601600
**subprocess_kwargs
602601
):
603602
"""Handles executing the command on the shell and consumes and returns
@@ -643,6 +642,11 @@ def execute(self, command,
643642
644643
:param env:
645644
A dictionary of environment variables to be passed to `subprocess.Popen`.
645+
646+
:param max_chunk_size:
647+
Maximum number of bytes in one chunk of data passed to the output_stream in
648+
one invocation of write() method. If the given number is not positive then
649+
the default value is used.
646650
647651
:param subprocess_kwargs:
648652
Keyword arguments to be passed to subprocess.Popen. Please note that
@@ -789,7 +793,8 @@ def _kill_process(pid):
789793
stderr_value = stderr_value[:-1]
790794
status = proc.returncode
791795
else:
792-
stream_copy(proc.stdout, output_stream, self.max_chunk_size)
796+
max_chunk_size = max_chunk_size if max_chunk_size and max_chunk_size > 0 else io.DEFAULT_BUFFER_SIZE
797+
stream_copy(proc.stdout, output_stream, max_chunk_size)
793798
stdout_value = output_stream
794799
stderr_value = proc.stderr.read()
795800
# strip trailing "\n"

git/test/test_repo.py

+25-9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# This module is part of GitPython and is released under
66
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
77
import glob
8+
import io
89
from io import BytesIO
910
import itertools
1011
import os
@@ -201,6 +202,21 @@ def _assert_empty_repo(self, repo):
201202
pass
202203
# END test repos with working tree
203204

205+
@with_rw_repo('HEAD')
206+
def test_max_chunk_size(self, repo):
207+
class TestOutputStream(object):
208+
def __init__(self, max_chunk_size):
209+
self.max_chunk_size = max_chunk_size
210+
211+
def write(self, b):
212+
assert_true(len(b) <= self.max_chunk_size)
213+
214+
for chunk_size in [16, 128, 1024]:
215+
repo.git.status(output_stream=TestOutputStream(chunk_size), max_chunk_size=chunk_size)
216+
217+
repo.git.log(n=100, output_stream=TestOutputStream(io.DEFAULT_BUFFER_SIZE), max_chunk_size=None)
218+
repo.git.log(n=100, output_stream=TestOutputStream(io.DEFAULT_BUFFER_SIZE))
219+
204220
def test_init(self):
205221
prev_cwd = os.getcwd()
206222
os.chdir(tempfile.gettempdir())
@@ -242,7 +258,7 @@ def test_init(self):
242258
# when relative paths are used, the clone may actually be inside
243259
# of the parent directory
244260
pass
245-
# END exception handling
261+
# END exception handling
246262

247263
# END for each path
248264

@@ -259,7 +275,7 @@ def test_init(self):
259275
except OSError:
260276
pass
261277
os.chdir(prev_cwd)
262-
# END restore previous state
278+
# END restore previous state
263279

264280
def test_bare_property(self):
265281
self.rorepo.bare
@@ -296,8 +312,8 @@ def test_is_dirty(self):
296312
for working_tree in (0, 1):
297313
for untracked_files in (0, 1):
298314
assert self.rorepo.is_dirty(index, working_tree, untracked_files) in (True, False)
299-
# END untracked files
300-
# END working tree
315+
# END untracked files
316+
# END working tree
301317
# END index
302318
orig_val = self.rorepo._bare
303319
self.rorepo._bare = True
@@ -456,7 +472,7 @@ def test_untracked_files(self, rwrepo):
456472
untracked_files = [win_encode(f) for f in untracked_files]
457473
repo_add(untracked_files)
458474
self.assertEqual(len(rwrepo.untracked_files), (num_recently_untracked - len(files)))
459-
# end for each run
475+
# end for each run
460476

461477
def test_config_reader(self):
462478
reader = self.rorepo.config_reader() # all config files
@@ -514,7 +530,7 @@ def test_tilde_and_env_vars_in_repo_path(self, rw_dir):
514530
if ph:
515531
os.environ['HOME'] = ph
516532
del os.environ['FOO']
517-
# end assure HOME gets reset to what it was
533+
# end assure HOME gets reset to what it was
518534

519535
def test_git_cmd(self):
520536
# test CatFileContentStream, just to be very sure we have no fencepost errors
@@ -681,7 +697,7 @@ def test_rev_parse(self):
681697
print("failed on %s" % path_section)
682698
# is fine, in case we have something like 112, which belongs to remotes/rname/merge-requests/112
683699
pass
684-
# END exception handling
700+
# END exception handling
685701
# END for each token
686702
if ref_no == 3 - 1:
687703
break
@@ -827,8 +843,8 @@ def last_commit(repo, rev, path):
827843
for repo_type in (GitCmdObjectDB, GitDB):
828844
repo = Repo(self.rorepo.working_tree_dir, odbt=repo_type)
829845
last_commit(repo, 'master', 'git/test/test_base.py')
830-
# end for each repository type
831-
# end for each iteration
846+
# end for each repository type
847+
# end for each iteration
832848

833849
def test_remote_method(self):
834850
self.failUnlessRaises(ValueError, self.rorepo.remote, 'foo-blue')

0 commit comments

Comments
 (0)