Skip to content

Commit c6e7c33

Browse files
committed
subprocess_run: allow stdout,stderr to be picked individually
1 parent a1e8d35 commit c6e7c33

File tree

3 files changed

+16
-17
lines changed

3 files changed

+16
-17
lines changed

+stdlib/subprocess_run.m

+15-14
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
% * opt.cwd: working directory to use while running command
1414
% * opt.stdin: string to pass to subprocess stdin pipe - OK to use with timeout
1515
% * opt.timeout: time to wait for process to complete before erroring (seconds)
16-
% * opt.outpipe: logical to indicate whether to use pipe for stdout and stderr (mutually exclusive with timeout option)
16+
% * opt.stdout: logical to indicate whether to use pipe for stdout
17+
% * opt.stderr: logical to indicate whether to use pipe for stderr
1718
%%% Outputs
1819
% * status: 0 is generally success. -1 if timeout. Other codes as per the
1920
% program / command run
@@ -38,11 +39,12 @@
3839
opt.cwd (1,1) string = ""
3940
opt.stdin (1,1) string = ""
4041
opt.timeout (1,1) int64 = 0
41-
opt.outpipe (1,1) logical = true
42+
opt.stdout (1,1) logical = true
43+
opt.stderr (1,1) logical = true
4244
end
4345

44-
if opt.outpipe && opt.timeout > 0
45-
error("outpipe and timeout options are mutually exclusive")
46+
if (opt.stdout || opt.stderr) && opt.timeout > 0
47+
error("stderr or stdout and timeout options are mutually exclusive")
4648
end
4749

4850
%% process instantiation
@@ -95,25 +97,26 @@
9597
% like Python subprocess.run, this may block or deadlock if the process writes
9698
% large amounts of data to stdout or stderr.
9799
% A better approach is to read each of the streams in a separate thread.
98-
if opt.outpipe
100+
101+
stdout = "";
102+
stderr = "";
103+
if opt.stdout && nargout > 1
99104
stdout = read_stream(h.getInputStream());
105+
end
106+
if opt.stderr && nargout > 2
100107
stderr = read_stream(h.getErrorStream());
101-
else
102-
stdout = "";
103-
stderr = "";
104108
end
105109
%% wait for process to complete
106110
% https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/lang/Process.html#waitFor()
107111

108-
tmsg = "";
109112
if opt.timeout > 0
110113
% returns true if process completed successfully
111114
% returns false if process did not complete within timeout
112115
b = h.waitFor(opt.timeout, java.util.concurrent.TimeUnit.SECONDS);
113116
if b
114117
status = 0;
115118
else
116-
tmsg = "Subprocess timeout";
119+
stderr = "Subprocess timeout";
117120
status = -1;
118121
end
119122
else
@@ -128,12 +131,10 @@
128131
setenv("GFORTRAN_STDERR_UNIT", errold);
129132
setenv("GFORTRAN_STDIN_UNIT", inold);
130133

131-
stderr = tmsg + stderr;
132-
133-
if nargout < 2 && strlength(stdout) > 0
134+
if nargout < 2 && opt.stdout && strlength(stdout) > 0
134135
disp(stdout)
135136
end
136-
if nargout < 3 && strlength(stderr) > 0
137+
if nargout < 3 && opt.stderr && strlength(stderr) > 0
137138
warning(stderr)
138139
end
139140

buildfile.m

-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
plan = buildplan(localfunctions);
55

6-
plan.DefaultTasks = "test";
7-
86
pkg_name = "+stdlib";
97

108
addpath(plan.RootFolder)

test/TestSubprocess.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ function test_timeout(tc)
9696
exe = cwd + "/sleep.exe";
9797
tc.assumeThat(exe, IsFile, exe + " not found")
9898

99-
[ret, ~, err] = stdlib.subprocess_run(exe, timeout=1, outpipe=false);
99+
[ret, ~, err] = stdlib.subprocess_run(exe, timeout=1, stdout=false, stderr=false);
100100

101101
tc.verifyNotEqual(ret, 0, err)
102102
tc.verifyThat(err, StartsWithSubstring("Subprocess timeout"))

0 commit comments

Comments
 (0)