1 /* 2 * Licensed under the Apache License, Version 2.0 (the "License"); 3 * you may not use this file except in compliance with the License. 4 * You may obtain a copy of the License at 5 * 6 * http://www.apache.org/licenses/LICENSE-2.0 7 * 8 * Unless required by applicable law or agreed to in writing, software 9 * distributed under the License is distributed on an "AS IS" BASIS, 10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 * See the License for the specific language governing permissions and 12 * limitations under the License. 13 */ 14 package org.apache.hadoop.maven.plugin.util; 15 16 import org.apache.maven.plugin.Mojo; 17 18 import java.io.BufferedReader; 19 import java.io.IOException; 20 import java.io.InputStream; 21 import java.io.InputStreamReader; 22 import java.io.UnsupportedEncodingException; 23 import java.util.ArrayList; 24 import java.util.List; 25 26 /** 27 * Exec is a helper class for executing an external process from a mojo. 28 */ 29 public class Exec { 30 private Mojo mojo; 31 32 /** 33 * Creates a new Exec instance for executing an external process from the given 34 * mojo. 35 * 36 * @param mojo Mojo executing external process 37 */ Exec(Mojo mojo)38 public Exec(Mojo mojo) { 39 this.mojo = mojo; 40 } 41 42 /** 43 * Runs the specified command and saves each line of the command's output to 44 * the given list. 45 * 46 * @param command List containing command and all arguments 47 * @param output List in/out parameter to receive command output 48 * @return int exit code of command 49 */ run(List<String> command, List<String> output)50 public int run(List<String> command, List<String> output) { 51 int retCode = 1; 52 ProcessBuilder pb = new ProcessBuilder(command); 53 try { 54 Process p = pb.start(); 55 OutputBufferThread stdOut = new OutputBufferThread(p.getInputStream()); 56 OutputBufferThread stdErr = new OutputBufferThread(p.getErrorStream()); 57 stdOut.start(); 58 stdErr.start(); 59 retCode = p.waitFor(); 60 if (retCode != 0) { 61 mojo.getLog().warn(command + " failed with error code " + retCode); 62 for (String s : stdErr.getOutput()) { 63 mojo.getLog().debug(s); 64 } 65 } 66 stdOut.join(); 67 stdErr.join(); 68 output.addAll(stdOut.getOutput()); 69 } catch (Exception ex) { 70 mojo.getLog().warn(command + " failed: " + ex.toString()); 71 } 72 return retCode; 73 } 74 75 /** 76 * OutputBufferThread is a background thread for consuming and storing output 77 * of the external process. 78 */ 79 private static class OutputBufferThread extends Thread { 80 private List<String> output; 81 private BufferedReader reader; 82 83 /** 84 * Creates a new OutputBufferThread to consume the given InputStream. 85 * 86 * @param is InputStream to consume 87 */ OutputBufferThread(InputStream is)88 public OutputBufferThread(InputStream is) { 89 this.setDaemon(true); 90 output = new ArrayList<String>(); 91 try { 92 reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); 93 } catch (UnsupportedEncodingException e) { 94 throw new RuntimeException("Unsupported encoding " + e.toString()); 95 } 96 } 97 98 @Override run()99 public void run() { 100 try { 101 String line = reader.readLine(); 102 while (line != null) { 103 output.add(line); 104 line = reader.readLine(); 105 } 106 } catch (IOException ex) { 107 throw new RuntimeException("make failed with error code " + ex.toString()); 108 } 109 } 110 111 /** 112 * Returns every line consumed from the input. 113 * 114 * @return List<String> every line consumed from the input 115 */ getOutput()116 public List<String> getOutput() { 117 return output; 118 } 119 } 120 } 121