Skip to content

Commit bcddc9b

Browse files
committed
[utils] Force subprocess output to be read in text mode
In Python 3, subprocess output is read as binary data by default, which isn’t what we want. Instead of reading process output as byte strings, then manually decoding them into strings, simply pass `text=True` to functions in the `subprocess` module, so that we get properly decoded strings right out the box. This fixes places that forget to do the decoding step — most especially, the `update-checkout` script. That script prints Git output as byte strings, which leads to unreadable results. Additionally, in shell.run, use the same pipe for capturing both stdout and stderr. The distinction is pretty pointless in this use case; however, keeping the two channels separate means that we lose the original ordering of printed messages, which does matter.
1 parent 30d3950 commit bcddc9b

File tree

5 files changed

+19
-21
lines changed

5 files changed

+19
-21
lines changed

utils/refactor-check-compiles.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
def run_cmd(cmd, desc):
1111
try:
12-
return subprocess.check_output(cmd)
12+
return subprocess.check_output(cmd, text=True)
1313
except subprocess.CalledProcessError:
1414
print('FAILED ' + desc + ':', file=sys.stderr)
1515
print(' '.join(cmd), file=sys.stderr)
@@ -130,7 +130,7 @@ def main():
130130
'-source-filename', args.source_filename,
131131
'-rewritten-output-file', temp_file_path,
132132
'-pos', args.pos
133-
] + extra_refactor_args + extra_both_args, desc='producing edit').decode("utf-8")
133+
] + extra_refactor_args + extra_both_args, desc='producing edit')
134134
sys.stdout.write(dump_text_output)
135135

136136
run_cmd([

utils/swift-darwin-postprocess.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ def main(arguments):
3232
# (rdar://78851265)
3333
def unrpathize(filename):
3434
dylibsOutput = subprocess.check_output(
35-
['xcrun', 'dyldinfo', '-dylibs', filename])
35+
['xcrun', 'dyldinfo', '-dylibs', filename],
36+
text=True)
3637

3738
# Do not rewrite @rpath-relative load commands for these libraries:
3839
# they are test support libraries that are never installed under
@@ -60,8 +61,7 @@ def unrpathize(filename):
6061

6162
# Build a command to invoke install_name_tool.
6263
command = ['install_name_tool']
63-
for binaryline in dylibsOutput.splitlines():
64-
line = binaryline.decode("utf-8", "strict")
64+
for line in dylibsOutput.splitlines():
6565
match = dylib_regex.match(line)
6666
if match and match.group('filename') not in allow_list:
6767
command.append('-change')

utils/swift-rpathize.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ def main(arguments):
5555

5656
def rpathize(filename):
5757
dylibsOutput = subprocess.check_output(
58-
['xcrun', 'dyldinfo', '-dylibs', filename])
58+
['xcrun', 'dyldinfo', '-dylibs', filename],
59+
text=True)
5960

6061
# The output from dyldinfo -dylibs is a line of header followed by one
6162
# install name per line, indented with spaces.
@@ -64,8 +65,7 @@ def rpathize(filename):
6465

6566
# Build a command to invoke install_name_tool.
6667
command = ['install_name_tool']
67-
for binaryline in dylibsOutput.splitlines():
68-
line = binaryline.decode("utf-8", "strict")
68+
for line in dylibsOutput.splitlines():
6969
match = dylib_regex.match(line)
7070
if match:
7171
command.append('-change')

utils/swift_build_support/swift_build_support/shell.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,11 @@ def capture(command, stderr=None, env=None, dry_run=None, echo=True,
132132
_env = dict(os.environ)
133133
_env.update(env)
134134
try:
135-
out = subprocess.check_output(command, env=_env, stderr=stderr)
136-
# Coerce to `str` hack. not py3 `byte`, not py2 `unicode`.
137-
return str(out.decode())
135+
return subprocess.check_output(command, env=_env, stderr=stderr,
136+
text=True)
138137
except subprocess.CalledProcessError as e:
139138
if allow_non_zero_exit:
140-
return str(e.output.decode())
139+
return e.output
141140
if optional:
142141
return None
143142
_fatal_error(
@@ -218,19 +217,18 @@ def run(*args, **kwargs):
218217
return(None, 0, args)
219218

220219
my_pipe = subprocess.Popen(
221-
*args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
222-
(stdout, stderr) = my_pipe.communicate()
220+
*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True,
221+
**kwargs)
222+
(output, _) = my_pipe.communicate()
223223
ret = my_pipe.wait()
224224

225225
if lock:
226226
lock.acquire()
227227
if echo_output:
228228
print(repo_path)
229229
_echo_command(dry_run, *args, env=env)
230-
if stdout:
231-
print(stdout, end="")
232-
if stderr:
233-
print(stderr, end="")
230+
if output:
231+
print(output, end="")
234232
print()
235233
if lock:
236234
lock.release()
@@ -240,6 +238,6 @@ def run(*args, **kwargs):
240238
eout.ret = ret
241239
eout.args = args
242240
eout.repo_path = repo_path
243-
eout.stderr = stderr
241+
eout.stderr = output
244242
raise eout
245-
return (stdout, 0, args)
243+
return (output, 0, args)

utils/update_checkout/update_checkout/update_checkout.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def check_parallel_results(results, op):
7070
print("%s failed (ret=%d): %s" % (r.repo_path, r.ret, r))
7171
fail_count += 1
7272
if r.stderr:
73-
print(r.stderr.decode('utf-8'))
73+
print(r.stderr)
7474
return fail_count
7575

7676

0 commit comments

Comments
 (0)