(command);
59 | return this;
60 | }
61 |
62 | /**
63 | * Replace the command line with the given varargs array of command line arguments.
64 | *
65 | * @param command the new array of command line arguments
66 | * @return this ProcessBuilder instance
67 | */
68 | public ProcessBuilder command(String... command) {
69 | this.command = Arrays.asList(command);
70 | return this;
71 | }
72 |
73 | /**
74 | * Returns a string map view of this process builder's environment. Whenever a process builder is created, the environment
75 | * is initialized to a copy of the current process environment (See {@link System#getenv()}). Subprocesses subsequently
76 | * started by this object's {@link #start()} method will use this map as their environment.
77 | *
78 | * The returned object may be modified using ordinary {@link Map} operators.
79 | *
80 | * @return
81 | * The process builder's environment.
82 | */
83 | public Map environment() {
84 | return this.env;
85 | }
86 |
87 | /**
88 | * Launch the subprocess and return a new {@link Process} instance.
89 | *
90 | * @return a new Process wrapping the child process's pid and IO streams
91 | */
92 | public Process start() {
93 | int[] stdin = new int[2];
94 | int[] stdout = new int[2];
95 | int[] stderr = new int[2];
96 |
97 | // prepare all pipes
98 | posix.pipe(stdin);
99 | posix.pipe(stdout);
100 | posix.pipe(stderr);
101 |
102 | // build env list
103 | ArrayList envp = new ArrayList();
104 | for (Map.Entry entry : env.entrySet()) {
105 | envp.add(entry.getKey() + "=" + entry.getValue());
106 | }
107 |
108 | // spawn process, closing parent's descriptors in child
109 | long pid = posix.posix_spawnp(
110 | command.get(0),
111 | Arrays.asList(
112 | SpawnFileAction.dup(stdin[0], 0),
113 | SpawnFileAction.dup(stdout[1], 1),
114 | SpawnFileAction.dup(stderr[1], 2),
115 | SpawnFileAction.close(stdin[1]),
116 | SpawnFileAction.close(stdout[0]),
117 | SpawnFileAction.close(stderr[0])),
118 | command,
119 | envp);
120 |
121 | // close child's descriptors in parent
122 | posix.close(stdin[0]);
123 | posix.close(stdout[1]);
124 | posix.close(stderr[1]);
125 |
126 | // construct a Process
127 | return new Process(posix, pid, stdin[1], stdout[0], stderr[0]);
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/test/java/jnr/process/TestProcessBuilder.java:
--------------------------------------------------------------------------------
1 | package jnr.process;
2 |
3 | import static org.junit.Assert.*;
4 | import org.junit.Test;
5 |
6 | import java.nio.channels.SelectableChannel;
7 | import java.nio.channels.SelectionKey;
8 | import java.nio.channels.Selector;
9 |
10 | /**
11 | * Created by headius on 1/19/15.
12 | */
13 | public class TestProcessBuilder {
14 | @Test
15 | public void testBasicProcess() throws Exception {
16 | ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "echo hello");
17 |
18 | Process p = pb.start();
19 |
20 | byte[] hello = new byte[5];
21 | p.getInputStream().read(hello);
22 |
23 | assertEquals(0, p.waitFor());
24 |
25 | assertArrayEquals("hello".getBytes(), hello);
26 | }
27 |
28 | @Test
29 | public void testEnvironmentVariables() throws Exception {
30 | String value = "environment variable";
31 |
32 | ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "echo \"$envVar\"");
33 | pb.environment().put("envVar", value);
34 |
35 | Process p = pb.start();
36 |
37 | byte[] message = new byte[value.getBytes().length];
38 | p.getInputStream().read(message);
39 |
40 | assertEquals(0, p.waitFor());
41 | assertArrayEquals(value.getBytes(), message);
42 | }
43 |
44 | @Test
45 | public void testSelectableIn() throws Exception {
46 | ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "echo hello");
47 |
48 | Process p = pb.start();
49 |
50 | SelectableChannel in = p.getIn();
51 |
52 | in.configureBlocking(false);
53 | Selector selector = in.provider().openSelector();
54 | SelectionKey key = in.register(selector, SelectionKey.OP_READ);
55 | int selected = selector.select();
56 |
57 | assertEquals(1, selected);
58 | assertEquals(key, selector.keys().iterator().next());
59 |
60 | selector.close();
61 | in.configureBlocking(true);
62 |
63 | byte[] hello = new byte[5];
64 | p.getInputStream().read(hello);
65 |
66 | assertEquals(0, p.waitFor());
67 |
68 | assertArrayEquals("hello".getBytes(), hello);
69 | }
70 |
71 | @Test
72 | public void testSelectableErr() throws Exception {
73 | ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "echo hello >&2");
74 |
75 | Process p = pb.start();
76 |
77 | SelectableChannel err = p.getErr();
78 |
79 | err.configureBlocking(false);
80 | Selector selector = err.provider().openSelector();
81 | SelectionKey key = err.register(selector, SelectionKey.OP_READ);
82 | int selected = selector.select();
83 |
84 | assertEquals(1, selected);
85 | assertEquals(key, selector.keys().iterator().next());
86 |
87 | selector.close();
88 | err.configureBlocking(true);
89 |
90 | byte[] hello = new byte[5];
91 | p.getErrorStream().read(hello);
92 |
93 | assertEquals(0, p.waitFor());
94 |
95 | assertArrayEquals("hello".getBytes(), hello);
96 | }
97 |
98 | @Test
99 | public void testSelectableOut() throws Exception {
100 | ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "cat");
101 |
102 | Process p = pb.start();
103 |
104 | SelectableChannel out = p.getOut();
105 |
106 | out.configureBlocking(false);
107 | Selector selector = out.provider().openSelector();
108 | SelectionKey key = out.register(selector, SelectionKey.OP_WRITE);
109 | int selected = selector.select();
110 |
111 | assertEquals(1, selected);
112 | assertEquals(key, selector.keys().iterator().next());
113 |
114 | selector.close();
115 | out.configureBlocking(true);
116 |
117 | p.getOutputStream().write("hello".getBytes());
118 |
119 | byte[] hello = new byte[5];
120 | p.getInputStream().read(hello);
121 |
122 | p.kill();
123 |
124 | assertEquals(9, p.waitFor());
125 |
126 | assertArrayEquals("hello".getBytes(), hello);
127 | }
128 | }
129 |
--------------------------------------------------------------------------------