Skip to content

Commit de11340

Browse files
committed
vcs: capture subprocess stdout only
1 parent 6dda539 commit de11340

File tree

7 files changed

+63
-21
lines changed

7 files changed

+63
-21
lines changed

news/8876.bugfix.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed hanging VCS subprocess calls when the VCS outputs a large amount of data
2+
on stderr. Restored logging of VCS errors that was inadvertently removed in pip
3+
20.2.

src/pip/_internal/utils/subprocess.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,6 @@ def call_subprocess(
190190
cwd=cwd,
191191
env=env,
192192
)
193-
assert proc.stdin
194-
assert proc.stdout
195-
proc.stdin.close()
196193
except Exception as exc:
197194
if log_failed_cmd:
198195
subprocess_logger.critical(
@@ -201,7 +198,10 @@ def call_subprocess(
201198
raise
202199
all_output = []
203200
if not stdout_only:
204-
# In this mode, stdout and stderr are in the same pip.
201+
assert proc.stdout
202+
assert proc.stdin
203+
proc.stdin.close()
204+
# In this mode, stdout and stderr are in the same pipe.
205205
while True:
206206
# The "line" value is a unicode string in Python 2.
207207
line = console_to_str(proc.stdout.readline())
@@ -224,7 +224,7 @@ def call_subprocess(
224224
output = ''.join(all_output)
225225
else:
226226
# In this mode, stdout and stderr are in different pipes.
227-
# We must use the communicate which is the only safe way to read both.
227+
# We must use communicate() which is the only safe way to read both.
228228
out_bytes, err_bytes = proc.communicate()
229229
# log line by line to preserve pip log indenting
230230
out = console_to_str(out_bytes)

src/pip/_internal/vcs/bazaar.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ def get_url_rev_and_auth(cls, url):
9393

9494
@classmethod
9595
def get_remote_url(cls, location):
96-
urls = cls.run_command(['info'], show_stdout=False, cwd=location)
96+
urls = cls.run_command(
97+
['info'], show_stdout=False, stdout_only=True, cwd=location
98+
)
9799
for line in urls.splitlines():
98100
line = line.strip()
99101
for x in ('checkout of branch: ',
@@ -108,7 +110,7 @@ def get_remote_url(cls, location):
108110
@classmethod
109111
def get_revision(cls, location):
110112
revision = cls.run_command(
111-
['revno'], show_stdout=False, cwd=location,
113+
['revno'], show_stdout=False, stdout_only=True, cwd=location,
112114
)
113115
return revision.splitlines()[-1]
114116

src/pip/_internal/vcs/git.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ def is_immutable_rev_checkout(self, url, dest):
7979

8080
def get_git_version(self):
8181
VERSION_PFX = 'git version '
82-
version = self.run_command(['version'], show_stdout=False)
82+
version = self.run_command(
83+
['version'], show_stdout=False, stdout_only=True
84+
)
8385
if version.startswith(VERSION_PFX):
8486
version = version[len(VERSION_PFX):].split()[0]
8587
else:
@@ -102,7 +104,11 @@ def get_current_branch(cls, location):
102104
# and to suppress the message to stderr.
103105
args = ['symbolic-ref', '-q', 'HEAD']
104106
output = cls.run_command(
105-
args, extra_ok_returncodes=(1, ), show_stdout=False, cwd=location,
107+
args,
108+
extra_ok_returncodes=(1, ),
109+
show_stdout=False,
110+
stdout_only=True,
111+
cwd=location,
106112
)
107113
ref = output.strip()
108114

@@ -135,8 +141,13 @@ def get_revision_sha(cls, dest, rev):
135141
rev: the revision name.
136142
"""
137143
# Pass rev to pre-filter the list.
138-
output = cls.run_command(['show-ref', rev], cwd=dest,
139-
show_stdout=False, on_returncode='ignore')
144+
output = cls.run_command(
145+
['show-ref', rev],
146+
cwd=dest,
147+
show_stdout=False,
148+
stdout_only=True,
149+
on_returncode='ignore',
150+
)
140151
refs = {}
141152
for line in output.strip().splitlines():
142153
try:
@@ -310,7 +321,10 @@ def get_remote_url(cls, location):
310321
# exits with return code 1 if there are no matching lines.
311322
stdout = cls.run_command(
312323
['config', '--get-regexp', r'remote\..*\.url'],
313-
extra_ok_returncodes=(1, ), show_stdout=False, cwd=location,
324+
extra_ok_returncodes=(1, ),
325+
show_stdout=False,
326+
stdout_only=True,
327+
cwd=location,
314328
)
315329
remotes = stdout.splitlines()
316330
try:
@@ -346,7 +360,10 @@ def get_revision(cls, location, rev=None):
346360
if rev is None:
347361
rev = 'HEAD'
348362
current_rev = cls.run_command(
349-
['rev-parse', rev], show_stdout=False, cwd=location,
363+
['rev-parse', rev],
364+
show_stdout=False,
365+
stdout_only=True,
366+
cwd=location,
350367
)
351368
return current_rev.strip()
352369

@@ -359,7 +376,10 @@ def get_subdirectory(cls, location):
359376
# find the repo root
360377
git_dir = cls.run_command(
361378
['rev-parse', '--git-dir'],
362-
show_stdout=False, cwd=location).strip()
379+
show_stdout=False,
380+
stdout_only=True,
381+
cwd=location,
382+
).strip()
363383
if not os.path.isabs(git_dir):
364384
git_dir = os.path.join(location, git_dir)
365385
repo_root = os.path.abspath(os.path.join(git_dir, '..'))
@@ -418,6 +438,7 @@ def get_repository_root(cls, location):
418438
['rev-parse', '--show-toplevel'],
419439
cwd=location,
420440
show_stdout=False,
441+
stdout_only=True,
421442
on_returncode='raise',
422443
log_failed_cmd=False,
423444
)

src/pip/_internal/vcs/mercurial.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ def update(self, dest, url, rev_options):
9292
def get_remote_url(cls, location):
9393
url = cls.run_command(
9494
['showconfig', 'paths.default'],
95-
show_stdout=False, cwd=location).strip()
95+
show_stdout=False,
96+
stdout_only=True,
97+
cwd=location,
98+
).strip()
9699
if cls._is_local_repository(url):
97100
url = path_to_url(url)
98101
return url.strip()
@@ -104,7 +107,10 @@ def get_revision(cls, location):
104107
"""
105108
current_revision = cls.run_command(
106109
['parents', '--template={rev}'],
107-
show_stdout=False, cwd=location).strip()
110+
show_stdout=False,
111+
stdout_only=True,
112+
cwd=location,
113+
).strip()
108114
return current_revision
109115

110116
@classmethod
@@ -115,7 +121,10 @@ def get_requirement_revision(cls, location):
115121
"""
116122
current_rev_hash = cls.run_command(
117123
['parents', '--template={node}'],
118-
show_stdout=False, cwd=location).strip()
124+
show_stdout=False,
125+
stdout_only=True,
126+
cwd=location,
127+
).strip()
119128
return current_rev_hash
120129

121130
@classmethod
@@ -131,7 +140,8 @@ def get_subdirectory(cls, location):
131140
"""
132141
# find the repo root
133142
repo_root = cls.run_command(
134-
['root'], show_stdout=False, cwd=location).strip()
143+
['root'], show_stdout=False, stdout_only=True, cwd=location
144+
).strip()
135145
if not os.path.isabs(repo_root):
136146
repo_root = os.path.abspath(os.path.join(location, repo_root))
137147
return find_path_to_setup_from_repo_root(location, repo_root)
@@ -146,6 +156,7 @@ def get_repository_root(cls, location):
146156
['root'],
147157
cwd=location,
148158
show_stdout=False,
159+
stdout_only=True,
149160
on_returncode='raise',
150161
log_failed_cmd=False,
151162
)

src/pip/_internal/vcs/subversion.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ def _get_svn_url_rev(cls, location):
167167
xml = cls.run_command(
168168
['info', '--xml', location],
169169
show_stdout=False,
170+
stdout_only=True,
170171
)
171172
url = _svn_info_xml_url_re.search(xml).group(1)
172173
revs = [
@@ -218,7 +219,9 @@ def call_vcs_version(self):
218219
# svn, version 1.12.0-SlikSvn (SlikSvn/1.12.0)
219220
# compiled May 28 2019, 13:44:56 on x86_64-microsoft-windows6.2
220221
version_prefix = 'svn, version '
221-
version = self.run_command(['--version'], show_stdout=False)
222+
version = self.run_command(
223+
['--version'], show_stdout=False, stdout_only=True
224+
)
222225
if not version.startswith(version_prefix):
223226
return ()
224227

src/pip/_internal/vcs/versioncontrol.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,8 @@ def run_command(
676676
command_desc=None, # type: Optional[str]
677677
extra_environ=None, # type: Optional[Mapping[str, Any]]
678678
spinner=None, # type: Optional[SpinnerInterface]
679-
log_failed_cmd=True # type: bool
679+
log_failed_cmd=True, # type: bool
680+
stdout_only=False, # type: bool
680681
):
681682
# type: (...) -> Text
682683
"""
@@ -693,7 +694,8 @@ def run_command(
693694
extra_environ=extra_environ,
694695
unset_environ=cls.unset_environ,
695696
spinner=spinner,
696-
log_failed_cmd=log_failed_cmd)
697+
log_failed_cmd=log_failed_cmd,
698+
stdout_only=stdout_only)
697699
except OSError as e:
698700
# errno.ENOENT = no such file or directory
699701
# In other words, the VCS executable isn't available

0 commit comments

Comments
 (0)