|
1 | | -function [status, msg] = subprocess_run(cmd_array, opt) |
2 | | - |
| 1 | +function [status, stdout, stderr] = subprocess_run(cmd, opt) |
| 2 | +% SUBPROCESS_RUN run a program with arguments and options |
| 3 | +% uses Matlab Java ProcessBuilder interface to run subprocess and use stdin/stdout pipes |
3 | 4 | arguments |
4 | | - cmd_array (1,:) string |
| 5 | + cmd (1,:) string |
5 | 6 | opt.env struct {mustBeScalarOrEmpty} = struct.empty |
6 | 7 | opt.cwd string {mustBeScalarOrEmpty} = string.empty |
| 8 | + opt.stdin string {mustBeScalarOrEmpty} = string.empty |
7 | 9 | end |
8 | 10 |
|
9 | | -exe = space_quote(cmd_array(1)); |
| 11 | +%% process instantiation |
| 12 | +proc = java.lang.ProcessBuilder(""); |
10 | 13 |
|
11 | | -if length(cmd_array) > 1 |
12 | | - cmd = append(exe, " ", join(cmd_array(2:end), " ")); |
13 | | -else |
14 | | - cmd = exe; |
| 14 | +if ~isempty(opt.env) |
| 15 | + % requires Parallel Computing Toolbox |
| 16 | + env = proc.environment(); |
| 17 | + fields = fieldnames(opt.env); |
| 18 | + for i = 1:length(fields) |
| 19 | + env.put(fields{i}, opt.env.(fields{i})); |
| 20 | + end |
15 | 21 | end |
16 | 22 |
|
17 | 23 | if ~isempty(opt.cwd) |
18 | 24 | mustBeFolder(opt.cwd) |
19 | | - cwd = stdlib.fileio.absolute_path(opt.cwd); |
20 | | - oldcwd = pwd; |
21 | | - cd(cwd) |
| 25 | + proc.directory(java.io.File(opt.cwd)); |
22 | 26 | end |
23 | 27 |
|
24 | | -old = isMATLABReleaseOlderThan('R2022b'); |
25 | | -if old && ~isempty(opt.env) |
26 | | - warning("Matlab >= R2022b required for 'env' option of subprocess_run()") |
| 28 | +proc.command(cmd); |
| 29 | +%% start process |
| 30 | +h = proc.start(); |
| 31 | + |
| 32 | +%% stdin pipe |
| 33 | +if ~isempty(opt.stdin) |
| 34 | + writer = java.io.BufferedWriter(java.io.OutputStreamWriter(h.getOutputStream())); |
| 35 | + writer.write(opt.stdin); |
| 36 | + writer.flush() |
| 37 | + writer.close() |
27 | 38 | end |
28 | 39 |
|
29 | | -if isempty(opt.env) || old |
30 | | - [status, msg] = system(cmd); |
31 | | -else |
32 | | - envCell = namedargs2cell(opt.env); |
33 | | - % https://www.mathworks.com/help/matlab/ref/system.html |
34 | | - [status, msg] = system(cmd, envCell{:}); |
| 40 | +%% wait for process to complete |
| 41 | +% https://docs.oracle.com/javase/9/docs/api/java/lang/Process.html#waitFor-- |
| 42 | +status = h.waitFor(); |
| 43 | + |
| 44 | +%% read stdout, stderr pipes |
| 45 | +stdout = read_stream(h.getInputStream()); |
| 46 | +stderr = read_stream(h.getErrorStream()); |
| 47 | + |
| 48 | +%% close process |
| 49 | +h.destroy() |
| 50 | + |
| 51 | +if nargout < 2 && strlength(stdout) > 0 |
| 52 | + disp(stdout) |
35 | 53 | end |
36 | | -if ~isempty(opt.cwd) |
37 | | - cd(oldcwd) |
| 54 | +if nargout < 3 && strlength(stderr) > 0 |
| 55 | + warning(stderr) |
38 | 56 | end |
39 | 57 |
|
40 | | -end |
| 58 | +end % function subprocess_run |
41 | 59 |
|
42 | 60 |
|
43 | | -function q = space_quote(p) |
44 | | -arguments |
45 | | - p (1,1) string |
46 | | -end |
| 61 | +function msg = read_stream(stream) |
47 | 62 |
|
48 | | -if ~contains(p, " ") |
49 | | - q = p; |
50 | | - return |
| 63 | +reader = java.io.BufferedReader(java.io.InputStreamReader(stream)); |
| 64 | +line = reader.readLine(); |
| 65 | +msg = ""; |
| 66 | +while ~isempty(line) |
| 67 | + msg = append(msg, string(line), newline); |
| 68 | + line = reader.readLine(); |
51 | 69 | end |
52 | | - |
53 | | -q = append('"', p, '"'); |
| 70 | +msg = strip(msg); |
| 71 | +reader.close() |
54 | 72 |
|
55 | 73 | end |
0 commit comments