View Javadoc

1   /*
2    * #%L
3    * Native ARchive plugin for Maven
4    * %%
5    * Copyright (C) 2002 - 2014 NAR Maven Plugin developers.
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   * 
11   * http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  // BEGINFREEHEP, fully replaced with a runner with threads
21  package com.github.maven_nar.cpptasks.compiler;
22  
23  import java.io.BufferedReader;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.InputStreamReader;
27  import java.io.OutputStream;
28  import java.util.Vector;
29  
30  import org.apache.tools.ant.taskdefs.Execute;
31  import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
32  
33  /**
34   * Implements ExecuteStreamHandler to capture the output of a Execute to an
35   * array of strings
36   *
37   * @author Curt Arnold
38   */
39  public class CaptureStreamHandler implements ExecuteStreamHandler {
40  
41    static class Copier extends Thread {
42      InputStream is;
43  
44      Vector<String> lines;
45  
46      Copier(final InputStream is) {
47        this.is = is;
48        this.lines = new Vector<>(10);
49      }
50  
51      public Vector<String> getLines() {
52        return this.lines;
53      }
54  
55      @Override
56      public void run() {
57        try {
58          final BufferedReader reader = new BufferedReader(new InputStreamReader(this.is));
59          while (true) {
60            final String line = reader.readLine();
61            if (line == null) {
62              break;
63            }
64            this.lines.addElement(line);
65          }
66        } catch (final IOException e) {
67          // Ignore
68        }
69      }
70    }
71  
72    /**
73     * Executes the given command, capturing the output using a newly allocated
74     * {@link CaptureStreamHandler}, which is then returned.
75     * <p>
76     * In contrast to {@link #run(String[])}, this method allows both the standard
77     * error and standard output streams to be inspected after execution (via the
78     * {@link #getStderr()} and {@link #getStdout()} methods, respectively).
79     * </p>
80     * 
81     * @param cmdline
82     *          command line arguments
83     * @return The {@link CaptureStreamHandler} used to capture the output.
84     */
85    public static CaptureStreamHandler execute(final String[] cmdline) {
86      final CaptureStreamHandler handler = new CaptureStreamHandler();
87      final Execute exec = new Execute(handler);
88      exec.setCommandline(cmdline);
89      try {
90        final int status = exec.execute();
91      } catch (final IOException ex) {
92      }
93      return handler;
94    }
95  
96    /**
97     * Runs an executable and captures the output in a String array
98     * 
99     * @param cmdline
100    *          command line arguments
101    * @return output of process
102    * @see CaptureStreamHandler#getOutput()
103    */
104   public static String[] run(final String[] cmdline) {
105     final CaptureStreamHandler handler = execute(cmdline);
106     return handler.getOutput() != null ? handler.getOutput() : new String[0];
107   }
108 
109   private String[] stderr;
110 
111   private String[] stdout;
112 
113   private InputStream processErrorStream;
114 
115   private InputStream processOutputStream;
116 
117   public CaptureStreamHandler() {
118   }
119 
120   /**
121    * Reads concurrently both the process standard output and standard error.
122    * The standard error is copied to the stderr string array field.
123    * The standard output is copied to the stdout string array field.
124    * Both fields are set to an empty array in case of any error.
125    */
126   public void gatherOutput() {
127     try {
128       final Copier errorCopier = new Copier(this.processErrorStream);
129       final Copier outputCopier = new Copier(this.processOutputStream);
130       errorCopier.start();
131       outputCopier.start();
132       errorCopier.join();
133       outputCopier.join();
134       this.stderr = new String[errorCopier.getLines().size()];
135       errorCopier.getLines().copyInto(this.stderr);
136       this.stdout = new String[outputCopier.getLines().size()];
137       outputCopier.getLines().copyInto(this.stdout);
138     } catch (final Exception e) {
139       this.stderr = this.stdout = new String[0];
140     }
141   }
142 
143   /**
144    * Gets the output of the execution. If standard error is not empty,
145    * it is returned; otherwise, standard output is returned.
146    */
147   public String[] getOutput() {
148     return null != this.stderr && this.stderr.length > 0 ? this.stderr : this.stdout;
149   }
150 
151   /** Gets the output of the execution's standard error stream. */
152   public String[] getStderr() {
153     return this.stderr;
154   }
155 
156   /** Gets the output of the execution's standard output stream. */
157   public String[] getStdout() {
158     return this.stdout;
159   }
160 
161   /**
162    * Install a handler for the error stream of the subprocess.
163    * 
164    * @param is
165    *          input stream to read from the error stream from the subprocess
166    */
167   @Override
168   public void setProcessErrorStream(final InputStream is) throws IOException {
169     this.processErrorStream = is;
170   }
171 
172   /**
173    * Install a handler for the input stream of the subprocess.
174    * 
175    * @param os
176    *          output stream to write to the standard input stream of the
177    *          subprocess
178    */
179   @Override
180   public void setProcessInputStream(final OutputStream os) throws IOException {
181     os.close();
182   }
183 
184   /**
185    * Install a handler for the output stream of the subprocess.
186    * 
187    * @param is
188    *          input stream to read from the error stream from the subprocess
189    */
190   @Override
191   public void setProcessOutputStream(final InputStream is) throws IOException {
192     this.processOutputStream = is;
193   }
194 
195   /**
196    * Start handling of the streams.
197    */
198   @Override
199   public void start() throws IOException {
200     gatherOutput();
201   }
202 
203   /**
204    * Stop handling of the streams - will not be restarted.
205    */
206   @Override
207   public void stop() {
208   }
209   // ENDFREEHEP
210 }