diff options
Diffstat (limited to 'jack-tests/src/com/android/jack/test/util/ExecuteFile.java')
-rw-r--r-- | jack-tests/src/com/android/jack/test/util/ExecuteFile.java | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/jack-tests/src/com/android/jack/test/util/ExecuteFile.java b/jack-tests/src/com/android/jack/test/util/ExecuteFile.java new file mode 100644 index 0000000..1f59b63 --- /dev/null +++ b/jack-tests/src/com/android/jack/test/util/ExecuteFile.java @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.jack.test.util; + +import com.android.sched.util.log.LoggerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.StreamTokenizer; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + +/** + * Class to handle the execution of an external process + */ +public class ExecuteFile { + @Nonnull + private final String[] cmdLine; + + @Nonnull + List<String> env = new ArrayList<String>(0); + + @CheckForNull + private File workDir; + + @CheckForNull + private InputStream inStream; + private boolean inToBeClose; + + @CheckForNull + private OutputStream outStream; + private boolean outToBeClose; + + @CheckForNull + private OutputStream errStream; + private boolean errToBeClose; + private boolean verbose; + + @Nonnull + private final Logger logger; + + public void setErr(@Nonnull File file) throws FileNotFoundException { + errStream = new FileOutputStream(file); + errToBeClose = true; + } + + public void setOut(@Nonnull File file) throws FileNotFoundException { + outStream = new FileOutputStream(file); + outToBeClose = true; + } + + public void setIn(@Nonnull File file) throws FileNotFoundException { + inStream = new FileInputStream(file); + inToBeClose = true; + } + + public void setErr(@Nonnull OutputStream stream) { + errStream = stream; + } + + public void setOut(@Nonnull OutputStream stream) { + outStream = stream; + } + + public void setIn(@Nonnull InputStream stream) { + inStream = stream; + } + + public void setWorkingDir(@Nonnull File dir, boolean create) throws IOException { + if (!dir.isDirectory()) { + if (create && !dir.exists()) { + if (!dir.mkdirs()) { + throw new IOException("Directory creation failed"); + } + } else { + throw new FileNotFoundException(dir.getPath() + " is not a directory"); + } + } + + workDir = dir; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + public void addEnvVar(@Nonnull String key, @Nonnull String value) { + env.add(key + "=" + value); + } + + public ExecuteFile(@Nonnull File exec, @Nonnull String[] args) { + cmdLine = new String[args.length + 1]; + System.arraycopy(args, 0, cmdLine, 1, args.length); + + cmdLine[0] = exec.getAbsolutePath(); + logger = LoggerFactory.getLogger(); + } + + public ExecuteFile(@Nonnull String exec, @Nonnull String[] args) { + cmdLine = new String[args.length + 1]; + System.arraycopy(args, 0, cmdLine, 1, args.length); + + cmdLine[0] = exec; + logger = LoggerFactory.getLogger(); + } + + public ExecuteFile(@Nonnull File exec) { + cmdLine = new String[1]; + cmdLine[0] = exec.getAbsolutePath(); + logger = LoggerFactory.getLogger(); + } + + public ExecuteFile(@Nonnull String[] cmdLine) { + this.cmdLine = cmdLine.clone(); + logger = LoggerFactory.getLogger(); + } + + public ExecuteFile(@Nonnull String cmdLine) throws IOException { + StringReader reader = new StringReader(cmdLine); + StreamTokenizer tokenizer = new StreamTokenizer(reader); + tokenizer.resetSyntax(); + // Only standard spaces are recognized as whitespace chars + tokenizer.whitespaceChars(' ', ' '); + // Matches alphanumerical and common special symbols like '(' and ')' + tokenizer.wordChars('!', 'z'); + // Quote chars will be ignored when parsing strings + tokenizer.quoteChar('\''); + tokenizer.quoteChar('\"'); + ArrayList<String> tokens = new ArrayList<String>(); + while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) { + String token = tokenizer.sval; + if (token != null) { + tokens.add(token); + } + } + this.cmdLine = tokens.toArray(new String[0]); + logger = LoggerFactory.getLogger(); + } + + public int run() throws ExecFileException { + int ret; + Process proc = null; + Thread suckOut = null; + Thread suckErr = null; + Thread suckIn = null; + + try { + StringBuilder cmdLineBuilder = new StringBuilder(); + for (String envElt : env) { + cmdLineBuilder.append(envElt).append(' '); + } + for (String arg : cmdLine) { + cmdLineBuilder.append(arg).append(' '); + } + if (verbose) { + PrintStream printStream; + if (outStream instanceof PrintStream) { + printStream = (PrintStream) outStream; + } else { + printStream = System.out; + } + + if (printStream != null) { + printStream.println(cmdLineBuilder); + } + } else { + logger.log(Level.INFO, "Execute: {0}", cmdLineBuilder); + } + + proc = Runtime.getRuntime().exec(cmdLine, env.toArray(new String[env.size()]), workDir); + + InputStream localInStream = inStream; + if (localInStream != null) { + suckIn = new Thread( + new ThreadBytesStreamSucker(localInStream, proc.getOutputStream(), inToBeClose)); + } else { + proc.getOutputStream().close(); + } + + OutputStream localOutStream = outStream; + if (localOutStream != null) { + if (localOutStream instanceof PrintStream) { + suckOut = new Thread(new ThreadCharactersStreamSucker(proc.getInputStream(), + (PrintStream) localOutStream, outToBeClose)); + } else { + suckOut = new Thread( + new ThreadBytesStreamSucker(proc.getInputStream(), localOutStream, outToBeClose)); + } + } + + OutputStream localErrStream = errStream; + if (localErrStream != null) { + if (localErrStream instanceof PrintStream) { + suckErr = new Thread(new ThreadCharactersStreamSucker(proc.getErrorStream(), + (PrintStream) localErrStream, errToBeClose)); + } else { + suckErr = new Thread( + new ThreadBytesStreamSucker(proc.getErrorStream(), localErrStream, errToBeClose)); + } + } + + if (suckIn != null) { + suckIn.start(); + } + if (suckOut != null) { + suckOut.start(); + } + if (suckErr != null) { + suckErr.start(); + } + + proc.waitFor(); + if (suckIn != null) { + suckIn.join(); + } + if (suckOut != null) { + suckOut.join(); + } + if (suckErr != null) { + suckErr.join(); + } + + ret = proc.exitValue(); + proc.destroy(); + + return ret; + } catch (Exception e) { + throw new ExecFileException(cmdLine, e); + } + } + + private static class ThreadBytesStreamSucker extends BytesStreamSucker implements Runnable { + + public ThreadBytesStreamSucker(@Nonnull InputStream is, @Nonnull OutputStream os, + boolean toBeClose) { + super(is, os, toBeClose); + } + + @Override + public void run() { + try { + suck(); + } catch (IOException e) { + // Best effort + } + } + } + + private static class ThreadCharactersStreamSucker extends CharactersStreamSucker implements + Runnable { + + public ThreadCharactersStreamSucker(@Nonnull InputStream is, @Nonnull PrintStream ps, + boolean toBeClose) { + super(is, ps, toBeClose); + } + + @Override + public void run() { + try { + suck(); + } catch (IOException e) { + // Best effort + } + } + } +}
\ No newline at end of file |