diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/windows/WindowsProcesses.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/windows/WindowsProcesses.java | 153 |
1 files changed, 151 insertions, 2 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/windows/WindowsProcesses.java b/src/main/java/com/google/devtools/build/lib/windows/WindowsProcesses.java index f6d62602b3..1f0c34e25a 100644 --- a/src/main/java/com/google/devtools/build/lib/windows/WindowsProcesses.java +++ b/src/main/java/com/google/devtools/build/lib/windows/WindowsProcesses.java @@ -14,6 +14,8 @@ package com.google.devtools.build.lib.windows; +import java.util.List; + /** * Process management on Windows. */ @@ -23,8 +25,106 @@ public class WindowsProcesses { // Prevent construction } - private static native String helloWorld(int arg, String fruit); - private static native int nativeGetpid(); + /** + * returns the PID of the current process. + */ + static native int nativeGetpid(); + + /** + * Creates a process with the specified Windows command line. + * + * <p>Appropriately quoting arguments is the responsibility of the caller. + * + * @param commandLine the command line (needs to be quoted Windows style) + * @param env the environment of the new process. null means inherit that of the Bazel server + * @param stdoutFile the file the stdout should be redirected to. if null, nativeReadStdout will + * work. + * @param stderrFile the file the stdout should be redirected to. if null, nativeReadStderr will + * work. + * @return the opaque identifier of the created process + */ + static native long nativeCreateProcess(String commandLine, byte[] env, String stdoutFile, + String stderrFile); + + /** + * Writes data from the given array to the stdin of the specified process. + * + * <p>Blocks until either some data was written or the process is terminated. + * + * @return the number of bytes written + */ + static native int nativeWriteStdin(long process, byte[] bytes, int offset, int length); + + /** + * Reads data from the stdout of the specified process into the given array. + * + * <p>Blocks until either some data was read or the process is terminated. + * + * @return the number of bytes read or -1 if there was an error. + */ + static native int nativeReadStdout(long process, byte[] bytes, int offset, int length); + + /** + * Reads data from the stderr of the specified process into the given array. + * + * <p>Blocks until either some data was read or the process is terminated. + * + * @return the number of bytes read or -1 if there was an error. + */ + static native int nativeReadStderr(long process, byte[] bytes, int offset, int length); + + /** + * Interrupts a {@link #nativeWaitFor(long) call on the specified process}. + * + * <p>Should only be called once on per process and only when a {@link #nativeWaitFor(long)} + * call is in progress. Otherwise its behavior is undefined. + * + * <p>The {@link #nativeWaitFor(long)} call will then return an error. + * + * <p>Does not modify the error state of the process. + */ + static native void nativeInterrupt(long process); + + /** + * Returns if the given process was interrupted by a {@link #nativeInterrupt(long)} call. + * + * <p>Does not modify the error state of the process. + */ + static native boolean nativeIsInterrupted(long process); + /** + * Waits until the given process terminates and returns with its exit code or -1 if there was an + * error. + */ + static native int nativeWaitFor(long process); + + /** + * Returns the process ID of the given process or -1 if there was an error. + */ + static native int nativeGetProcessPid(long process); + + /** + * Terminates the given process. Returns true if the termination was successful. + */ + static native boolean nativeTerminate(long process); + + /** + * Releases the native data structures associated with the process. + * + * <p>Calling any other method on the same process after this call will result in the JVM + * crashing or worse. + */ + static native void nativeDelete(long process); + + /** + * Returns a string representation of the last error caused by any call on the given process + * or the empty string if the last operation was successful. + * + * <p>Does <b>NOT</b> terminate the process if it is still running. + * + * <p>After this call returns, subsequent calls will return the empty string if there was no + * failed operation in between. + */ + static native String nativeGetLastError(long process); public static int getpid() { ensureJni(); @@ -39,4 +139,53 @@ public class WindowsProcesses { System.loadLibrary("windows_jni"); jniLoaded = true; } + + static String quoteCommandLine(List<String> argv) { + StringBuilder result = new StringBuilder(); + for (int iArg = 0; iArg < argv.size(); iArg++) { + if (iArg != 0) { + result.append(" "); + } + String arg = argv.get(iArg); + boolean hasSpace = arg.contains(" "); + if (!arg.contains("\"") && !arg.contains("\\") && !hasSpace) { + // fast path. Just append the input string. + result.append(arg); + } else { + // We need to quote things if the argument contains a space. + if (hasSpace) { + result.append("\""); + } + + for (int iChar = 0; iChar < arg.length(); iChar++) { + boolean lastChar = iChar == arg.length() - 1; + switch (arg.charAt(iChar)) { + case '"': + // Escape double quotes + result.append("\\\""); + break; + case '\\': + // Backslashes at the end of the string are quoted if we add quotes + if (lastChar) { + result.append(hasSpace ? "\\\\" : "\\"); + } else { + // Backslashes everywhere else are quoted if they are followed by a + // quote or a backslash + result.append(arg.charAt(iChar + 1) == '"' || arg.charAt(iChar + 1) == '\\' + ? "\\\\" : "\\"); + } + break; + default: + result.append(arg.charAt(iChar)); + } + } + // Add ending quotes if we added a quote at the beginning. + if (hasSpace) { + result.append("\""); + } + } + } + + return result.toString(); + } } |