grep: prevent external grep command writing stdout directly

Summary:
The external grep command (originally from fb-hgext's tweaks of grep command)
was run without redirecting its stdout. That could be problematic for
streampager, because writing directly to stdout will mess up with streampager
interface.

For example, the following command will show "nothing", while it should print
something:

  fbcode/antlir/fbpkg/build % lhg grep -l scuba --config pager.pager=internal:streampager --config grep.usebiggrep=False --config pager.interface=full

Fix it by using a PIPE and forward the external command's output to streampager
buffer properly.

Reviewed By: andll

Differential Revision: D29408821

fbshipit-source-id: 4b2a0a6bbd64aa00d09f921d830b173cc56ae630
This commit is contained in:
Jun Wu 2021-06-25 18:17:28 -07:00 committed by Facebook GitHub Bot
parent c4ca1d3a34
commit c00bc1ac2e

View File

@ -2968,7 +2968,7 @@ def grep(ui, repo, pattern, *pats, **opts):
# Ensure that the biggrep results are flushed before we
# start to intermingle with the local grep process output
ui.flush()
return _rungrep(cmd, sorted(filestogrep), m)
return _rungrep(ui, cmd, sorted(filestogrep), m)
return 0
@ -2978,19 +2978,31 @@ def grep(ui, repo, pattern, *pats, **opts):
files = [file for file in files if not islink(file)]
ui.pager("grep")
return _rungrep(cmd, files, m)
return _rungrep(ui, cmd, files, m)
def _rungrep(cmd, files, match):
p = subprocess.Popen(
cmd, bufsize=-1, close_fds=util.closefds, stdin=subprocess.PIPE
)
write = p.stdin.write
for f in files:
write(pycompat.encodeutf8(match.rel(f) + "\0"))
def _rungrep(ui, cmd, files, match):
import tempfile
p.stdin.close()
return p.wait()
with tempfile.NamedTemporaryFile("w+b", prefix="hg-grep") as ftmp:
for f in files:
ftmp.write(pycompat.encodeutf8(match.rel(f) + "\0"))
ftmp.flush()
ftmp.seek(0)
# XXX: stderr is not redirected to ui.write_err properly.
p = subprocess.Popen(
cmd,
bufsize=-1,
close_fds=util.closefds,
stdin=ftmp,
stdout=subprocess.PIPE,
)
write = ui.writebytes
for line in p.stdout:
write(line)
return p.wait()
@command(