blob: bae82eb6b1a643ed8ef70528af8e48a8a2a6aab7 [file] [log] [blame]
Stuart McCulloch26e7a5a2011-10-17 10:31:43 +00001package aQute.libg.command;
2
3import java.io.*;
4import java.util.*;
5import java.util.concurrent.*;
6
7import aQute.libg.reporter.*;
8
9public class Command {
10
11 boolean trace;
12 Reporter reporter;
13 List<String> arguments = new ArrayList<String>();
14 long timeout = 0;
15 File cwd = new File("").getAbsoluteFile();
16 static Timer timer = new Timer();
17 Process process;
18 volatile boolean timedout;
19
20 public int execute(Appendable stdout, Appendable stderr) throws Exception {
21 return execute((InputStream) null, stdout, stderr);
22 }
23
24 public int execute(String input, Appendable stdout, Appendable stderr) throws Exception {
25 InputStream in = new ByteArrayInputStream(input.getBytes("UTF-8"));
26 return execute(in, stdout, stderr);
27 }
28
29 public int execute(InputStream in, Appendable stdout, Appendable stderr) throws Exception {
30 int result;
31 if (reporter != null) {
32 reporter.trace("executing cmd: %s", arguments);
33 }
34
35 String args[] = arguments.toArray(new String[arguments.size()]);
36
37 process = Runtime.getRuntime().exec(args, null, cwd);
38
39 // Make sure the command will not linger when we go
40 Runnable r = new Runnable() {
41 public void run() {
42 process.destroy();
43 }
44 };
45 Thread hook = new Thread(r, arguments.toString());
46 Runtime.getRuntime().addShutdownHook(hook);
47 TimerTask timer = null;
48 OutputStream stdin = process.getOutputStream();
49 final InputStreamHandler handler = in != null ? new InputStreamHandler(in, stdin) : null;
50
51 if (timeout != 0) {
52 timer = new TimerTask() {
53 public void run() {
54 timedout = true;
55 process.destroy();
56 if (handler != null)
57 handler.interrupt();
58 }
59 };
60 Command.timer.schedule(timer, timeout);
61 }
62
63 InputStream out = process.getInputStream();
64 try {
65 InputStream err = process.getErrorStream();
66 try {
67 new Collector(out, stdout).start();
68 new Collector(err, stdout).start();
69 if (handler != null)
70 handler.start();
71
72 result = process.waitFor();
73 } finally {
74 err.close();
75 }
76 } finally {
77 out.close();
78 if (timer != null)
79 timer.cancel();
80 Runtime.getRuntime().removeShutdownHook(hook);
81 if (handler != null)
82 handler.interrupt();
83 }
84 if (reporter != null)
85 reporter.trace("cmd %s executed with result=%d, result: %s/%s", arguments, result,
86 stdout, stderr);
87
88 if( timedout )
89 return Integer.MIN_VALUE;
90 byte exitValue = (byte) process.exitValue();
91 return exitValue;
92 }
93
94 public void add(String... args) {
95 for (String arg : args)
96 arguments.add(arg);
97 }
98
99 public void addAll(Collection<String> args) {
100 arguments.addAll(args);
101 }
102
103 public void setTimeout(long duration, TimeUnit unit) {
104 timeout = unit.toMillis(duration);
105 }
106
107 public void setTrace() {
108 this.trace = true;
109 }
110
111 public void setReporter(Reporter reporter) {
112 this.reporter = reporter;
113 }
114
115 public void setCwd(File dir) {
116 if (!dir.isDirectory())
117 throw new IllegalArgumentException("Working directory must be a directory: " + dir);
118
119 this.cwd = dir;
120 }
121
122 public void cancel() {
123 process.destroy();
124 }
125
126 class Collector extends Thread {
127 final InputStream in;
128 final Appendable sb;
129
130 public Collector(InputStream inputStream, Appendable sb) {
131 this.in = inputStream;
132 this.sb = sb;
133 }
134
135 public void run() {
136 try {
137 int c = in.read();
138 while (c >= 0) {
139 if (trace)
140 System.out.print((char) c);
141 sb.append((char) c);
142 c = in.read();
143 }
144 } catch (Exception e) {
145 try {
146 sb.append("\n**************************************\n");
147 sb.append(e.toString());
148 sb.append("\n**************************************\n");
149 } catch (IOException e1) {
150 }
151 if (reporter != null) {
152 reporter.trace("cmd exec: %s", e);
153 }
154 }
155 }
156 }
157
158 class InputStreamHandler extends Thread {
159 final InputStream in;
160 final OutputStream stdin;
161
162 public InputStreamHandler(InputStream in, OutputStream stdin) {
163 this.stdin = stdin;
164 this.in = in;
165 }
166
167 public void run() {
168 try {
169 int c = in.read();
170 while (c >= 0) {
171 stdin.write(c);
172 stdin.flush();
173 c = in.read();
174 }
175 } catch (InterruptedIOException e) {
176 // Ignore here
177 } catch (Exception e) {
178 // Who cares?
179 }
180 }
181 }
182
183 public String toString() {
184 StringBuilder sb = new StringBuilder();
185 String del = "";
186
187 for (String argument : arguments) {
188 sb.append(del);
189 sb.append(argument);
190 del = " ";
191 }
192 return sb.toString();
193 }
194}