src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CommandExecutor.java
author hannesw
Wed, 21 Mar 2018 16:55:34 +0100
changeset 49275 c639a6b33c5c
parent 47216 71c04702a3d5
permissions -rw-r--r--
8199869: Missing copyright headers in nashorn source code Reviewed-by: sundar
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
     1
/*
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
     2
 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
     4
 *
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    10
 *
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    15
 * accompanied this code).
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    16
 *
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    20
 *
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    23
 * questions.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    24
 */
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    25
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    26
package jdk.nashorn.internal.runtime;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    27
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    28
import java.io.ByteArrayInputStream;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    29
import java.io.ByteArrayOutputStream;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    30
import java.io.File;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    31
import java.io.IOException;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    32
import java.io.InputStream;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    33
import java.io.OutputStream;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    34
import java.io.StreamTokenizer;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    35
import java.io.StringReader;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    36
import java.lang.ProcessBuilder.Redirect;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    37
import java.nio.file.Path;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    38
import java.nio.file.Paths;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    39
import java.security.AccessController;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    40
import java.security.PrivilegedAction;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    41
import java.util.ArrayList;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    42
import java.util.HashMap;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    43
import java.util.Iterator;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    44
import java.util.List;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    45
import java.util.Map;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    46
import java.util.concurrent.TimeUnit;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    47
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    48
import static jdk.nashorn.internal.runtime.CommandExecutor.RedirectType.*;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    49
import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    50
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    51
/**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    52
 * The CommandExecutor class provides support for Nashorn's $EXEC
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    53
 * builtin function. CommandExecutor provides support for command parsing,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    54
 * I/O redirection, piping, completion timeouts, # comments, and simple
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    55
 * environment variable management (cd, setenv, and unsetenv).
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    56
 */
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    57
class CommandExecutor {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    58
    // Size of byte buffers used for piping.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    59
    private static final int BUFFER_SIZE = 1024;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    60
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    61
    // Test to see if running on Windows.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    62
    private static final boolean IS_WINDOWS =
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    63
        AccessController.doPrivileged((PrivilegedAction<Boolean>)() -> {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    64
        return System.getProperty("os.name").contains("Windows");
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    65
    });
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    66
36479
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
    67
    // Cygwin drive alias prefix.
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
    68
    private static final String CYGDRIVE = "/cygdrive/";
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
    69
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    70
    // User's home directory
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    71
    private static final String HOME_DIRECTORY =
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    72
        AccessController.doPrivileged((PrivilegedAction<String>)() -> {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    73
        return System.getProperty("user.home");
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    74
    });
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    75
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    76
    // Various types of standard redirects.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    77
    enum RedirectType {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    78
        NO_REDIRECT,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    79
        REDIRECT_INPUT,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    80
        REDIRECT_OUTPUT,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    81
        REDIRECT_OUTPUT_APPEND,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    82
        REDIRECT_ERROR,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    83
        REDIRECT_ERROR_APPEND,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    84
        REDIRECT_OUTPUT_ERROR_APPEND,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    85
        REDIRECT_ERROR_TO_OUTPUT
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    86
    };
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    87
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    88
    // Prefix strings to standard redirects.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    89
    private static final String[] redirectPrefixes = new String[] {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    90
        "<",
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    91
        "0<",
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    92
        ">",
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    93
        "1>",
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    94
        ">>",
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    95
        "1>>",
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    96
        "2>",
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    97
        "2>>",
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    98
        "&>",
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
    99
        "2>&1"
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   100
    };
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   101
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   102
    // Map from redirectPrefixes to RedirectType.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   103
    private static final RedirectType[] redirects = new RedirectType[] {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   104
        REDIRECT_INPUT,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   105
        REDIRECT_INPUT,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   106
        REDIRECT_OUTPUT,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   107
        REDIRECT_OUTPUT,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   108
        REDIRECT_OUTPUT_APPEND,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   109
        REDIRECT_OUTPUT_APPEND,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   110
        REDIRECT_ERROR,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   111
        REDIRECT_ERROR_APPEND,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   112
        REDIRECT_OUTPUT_ERROR_APPEND,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   113
        REDIRECT_ERROR_TO_OUTPUT
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   114
    };
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   115
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   116
    /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   117
     * The RedirectInfo class handles checking the next token in a command
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   118
     * to see if it contains a redirect.  If the redirect file does not butt
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   119
     * against the prefix, then the next token is consumed.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   120
     */
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   121
    private static class RedirectInfo {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   122
        // true if a redirect was encountered on the current command.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   123
        private boolean hasRedirects;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   124
        // Redirect.PIPE or an input redirect from the command line.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   125
        private Redirect inputRedirect;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   126
        // Redirect.PIPE or an output redirect from the command line.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   127
        private Redirect outputRedirect;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   128
        // Redirect.PIPE or an error redirect from the command line.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   129
        private Redirect errorRedirect;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   130
        // true if the error stream should be merged with output.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   131
        private boolean mergeError;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   132
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   133
        RedirectInfo() {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   134
            this.hasRedirects = false;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   135
            this.inputRedirect = Redirect.PIPE;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   136
            this.outputRedirect = Redirect.PIPE;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   137
            this.errorRedirect = Redirect.PIPE;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   138
            this.mergeError = false;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   139
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   140
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   141
        /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   142
         * check - tests to see if the current token contains a redirect
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   143
         * @param token    current command line token
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   144
         * @param iterator current command line iterator
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   145
         * @param cwd      current working directory
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   146
         * @return true if token is consumed
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   147
         */
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   148
        boolean check(String token, final Iterator<String> iterator, final String cwd) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   149
            // Iterate through redirect prefixes to file a match.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   150
            for (int i = 0; i < redirectPrefixes.length; i++) {
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   151
               final String prefix = redirectPrefixes[i];
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   152
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   153
               // If a match is found.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   154
                if (token.startsWith(prefix)) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   155
                    // Indicate we have at least one redirect (efficiency.)
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   156
                    hasRedirects = true;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   157
                    // Map prefix to RedirectType.
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   158
                    final RedirectType redirect = redirects[i];
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   159
                    // Strip prefix from token
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   160
                    token = token.substring(prefix.length());
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   161
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   162
                    // Get file from either current or next token.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   163
                    File file = null;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   164
                    if (redirect != REDIRECT_ERROR_TO_OUTPUT) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   165
                        // Nothing left of current token.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   166
                        if (token.length() == 0) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   167
                            if (iterator.hasNext()) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   168
                                // Use next token.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   169
                                token = iterator.next();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   170
                            } else {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   171
                                // Send to null device if not provided.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   172
                                token = IS_WINDOWS ? "NUL:" : "/dev/null";
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   173
                            }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   174
                        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   175
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   176
                        // Redirect file.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   177
                        file = resolvePath(cwd, token).toFile();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   178
                    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   179
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   180
                    // Define redirect based on prefix.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   181
                    switch (redirect) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   182
                        case REDIRECT_INPUT:
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   183
                            inputRedirect = Redirect.from(file);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   184
                            break;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   185
                        case REDIRECT_OUTPUT:
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   186
                            outputRedirect = Redirect.to(file);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   187
                            break;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   188
                        case REDIRECT_OUTPUT_APPEND:
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   189
                            outputRedirect = Redirect.appendTo(file);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   190
                            break;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   191
                        case REDIRECT_ERROR:
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   192
                            errorRedirect = Redirect.to(file);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   193
                            break;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   194
                        case REDIRECT_ERROR_APPEND:
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   195
                            errorRedirect = Redirect.appendTo(file);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   196
                            break;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   197
                        case REDIRECT_OUTPUT_ERROR_APPEND:
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   198
                            outputRedirect = Redirect.to(file);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   199
                            errorRedirect = Redirect.to(file);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   200
                            mergeError = true;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   201
                            break;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   202
                        case REDIRECT_ERROR_TO_OUTPUT:
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   203
                            mergeError = true;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   204
                            break;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   205
                        default:
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   206
                            return false;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   207
                    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   208
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   209
                    // Indicate token is consumed.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   210
                    return true;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   211
                }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   212
            }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   213
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   214
            // No redirect found.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   215
            return false;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   216
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   217
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   218
        /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   219
         * apply - apply the redirects to the current ProcessBuilder.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   220
         * @param pb current ProcessBuilder
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   221
         */
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   222
        void apply(final ProcessBuilder pb) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   223
            // Only if there was redirects (saves new structure in ProcessBuilder.)
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   224
            if (hasRedirects) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   225
                // If output and error are the same file then merge.
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   226
                final File outputFile = outputRedirect.file();
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   227
                final File errorFile = errorRedirect.file();
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   228
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   229
                if (outputFile != null && outputFile.equals(errorFile)) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   230
                    mergeError = true;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   231
                }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   232
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   233
                // Apply redirects.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   234
                pb.redirectInput(inputRedirect);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   235
                pb.redirectOutput(outputRedirect);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   236
                pb.redirectError(errorRedirect);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   237
                pb.redirectErrorStream(mergeError);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   238
            }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   239
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   240
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   241
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   242
    /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   243
     * The Piper class is responsible for copying from an InputStream to an
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   244
     * OutputStream without blocking the current thread.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   245
     */
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   246
    private static class Piper implements java.lang.Runnable {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   247
        // Stream to copy from.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   248
        private final InputStream input;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   249
        // Stream to copy to.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   250
        private final OutputStream output;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   251
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   252
        private final Thread thread;
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   253
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   254
        Piper(final InputStream input, final OutputStream output) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   255
            this.input = input;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   256
            this.output = output;
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   257
            this.thread = new Thread(this, "$EXEC Piper");
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   258
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   259
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   260
        /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   261
         * start - start the Piper in a new daemon thread
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   262
         * @return this Piper
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   263
         */
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   264
        Piper start() {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   265
            thread.setDaemon(true);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   266
            thread.start();
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   267
            return this;
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   268
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   269
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   270
        /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   271
         * run - thread action
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   272
         */
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   273
        @Override
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   274
        public void run() {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   275
            try {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   276
                // Buffer for copying.
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   277
                final byte[] b = new byte[BUFFER_SIZE];
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   278
                // Read from the InputStream until EOF.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   279
                int read;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   280
                while (-1 < (read = input.read(b, 0, b.length))) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   281
                    // Write available date to OutputStream.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   282
                    output.write(b, 0, read);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   283
                }
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   284
            } catch (final Exception e) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   285
                // Assume the worst.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   286
                throw new RuntimeException("Broken pipe", e);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   287
            } finally {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   288
                // Make sure the streams are closed.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   289
                try {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   290
                    input.close();
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   291
                } catch (final IOException e) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   292
                    // Don't care.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   293
                }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   294
                try {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   295
                    output.close();
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   296
                } catch (final IOException e) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   297
                    // Don't care.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   298
                }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   299
            }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   300
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   301
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   302
        public void join() throws InterruptedException {
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   303
            thread.join();
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   304
        }
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   305
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   306
        // Exit thread.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   307
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   308
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   309
    // Process exit statuses.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   310
    static final int EXIT_SUCCESS  =  0;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   311
    static final int EXIT_FAILURE  =  1;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   312
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   313
    // Copy of environment variables used by all processes.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   314
    private  Map<String, String> environment;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   315
    // Input string if provided on CommandExecutor call.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   316
    private String inputString;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   317
    // Output string if required from CommandExecutor call.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   318
    private String outputString;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   319
    // Error string if required from CommandExecutor call.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   320
    private String errorString;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   321
    // Last process exit code.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   322
    private int exitCode;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   323
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   324
    // Input stream if provided on CommandExecutor call.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   325
    private InputStream inputStream;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   326
    // Output stream if provided on CommandExecutor call.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   327
    private OutputStream outputStream;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   328
    // Error stream if provided on CommandExecutor call.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   329
    private OutputStream errorStream;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   330
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   331
    // Ordered collection of current or piped ProcessBuilders.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   332
    private List<ProcessBuilder> processBuilders = new ArrayList<>();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   333
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   334
    CommandExecutor() {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   335
        this.environment = new HashMap<>();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   336
        this.inputString = "";
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   337
        this.outputString = "";
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   338
        this.errorString = "";
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   339
        this.exitCode = EXIT_SUCCESS;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   340
        this.inputStream = null;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   341
        this.outputStream = null;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   342
        this.errorStream = null;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   343
        this.processBuilders = new ArrayList<>();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   344
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   345
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   346
    /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   347
     * envVarValue - return the value of the environment variable key, or
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   348
     * deflt if not found.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   349
     * @param key   name of environment variable
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   350
     * @param deflt value to return if not found
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   351
     * @return value of the environment variable
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   352
     */
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   353
    private String envVarValue(final String key, final String deflt) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   354
        return environment.getOrDefault(key, deflt);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   355
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   356
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   357
    /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   358
     * envVarLongValue - return the value of the environment variable key as a
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   359
     * long value.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   360
     * @param key name of environment variable
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   361
     * @return long value of the environment variable
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   362
     */
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   363
    private long envVarLongValue(final String key) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   364
        try {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   365
            return Long.parseLong(envVarValue(key, "0"));
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   366
        } catch (final NumberFormatException ex) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   367
            return 0L;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   368
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   369
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   370
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   371
    /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   372
     * envVarBooleanValue - return the value of the environment variable key as a
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   373
     * boolean value.  true if the value was non-zero, false otherwise.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   374
     * @param key name of environment variable
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   375
     * @return boolean value of the environment variable
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   376
     */
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   377
    private boolean envVarBooleanValue(final String key) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   378
        return envVarLongValue(key) != 0;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   379
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   380
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   381
    /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   382
     * stripQuotes - strip quotes from token if present. Quoted tokens kept
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   383
     * quotes to prevent search for redirects.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   384
     * @param token token to strip
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   385
     * @return stripped token
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   386
     */
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   387
    private static String stripQuotes(String token) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   388
        if ((token.startsWith("\"") && token.endsWith("\"")) ||
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   389
             token.startsWith("\'") && token.endsWith("\'")) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   390
            token = token.substring(1, token.length() - 1);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   391
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   392
        return token;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   393
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   394
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   395
    /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   396
     * resolvePath - resolves a path against a current working directory.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   397
     * @param cwd      current working directory
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   398
     * @param fileName name of file or directory
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   399
     * @return resolved Path to file
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   400
     */
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   401
    private static Path resolvePath(final String cwd, final String fileName) {
36479
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   402
        return Paths.get(sanitizePath(cwd)).resolve(fileName).normalize();
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   403
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   404
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   405
    /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   406
     * builtIn - checks to see if the command is a builtin and performs
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   407
     * appropriate action.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   408
     * @param cmd current command
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   409
     * @param cwd current working directory
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   410
     * @return true if was a builtin command
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   411
     */
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   412
    private boolean builtIn(final List<String> cmd, final String cwd) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   413
        switch (cmd.get(0)) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   414
            // Set current working directory.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   415
            case "cd":
36479
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   416
                final boolean cygpath = IS_WINDOWS && cwd.startsWith(CYGDRIVE);
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   417
                // If zero args then use home directory as cwd else use first arg.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   418
                final String newCWD = cmd.size() < 2 ? HOME_DIRECTORY : cmd.get(1);
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   419
                // Normalize the cwd
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   420
                final Path cwdPath = resolvePath(cwd, newCWD);
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   421
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   422
                // Check if is a directory.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   423
                final File file = cwdPath.toFile();
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   424
                if (!file.exists()) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   425
                    reportError("file.not.exist", file.toString());
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   426
                    return true;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   427
                } else if (!file.isDirectory()) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   428
                    reportError("not.directory", file.toString());
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   429
                    return true;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   430
                }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   431
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   432
                // Set PWD environment variable to be picked up as cwd.
36479
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   433
                // Make sure Cygwin paths look like Unix paths.
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   434
                String scwd = cwdPath.toString();
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   435
                if (cygpath && scwd.length() >= 2 &&
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   436
                        Character.isLetter(scwd.charAt(0)) && scwd.charAt(1) == ':') {
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   437
                    scwd = CYGDRIVE + Character.toLowerCase(scwd.charAt(0)) + "/" + scwd.substring(2);
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   438
                }
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   439
                environment.put("PWD", scwd);
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   440
                return true;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   441
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   442
            // Set an environment variable.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   443
            case "setenv":
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   444
                if (3 <= cmd.size()) {
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   445
                    final String key = cmd.get(1);
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   446
                    final String value = cmd.get(2);
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   447
                    environment.put(key, value);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   448
                }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   449
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   450
                return true;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   451
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   452
            // Unset an environment variable.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   453
            case "unsetenv":
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   454
                if (2 <= cmd.size()) {
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   455
                    final String key = cmd.get(1);
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   456
                    environment.remove(key);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   457
                }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   458
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   459
                return true;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   460
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   461
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   462
        return false;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   463
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   464
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   465
    /**
36479
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   466
     * preprocessCommand - scan the command for redirects, and sanitize the
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   467
     * executable path
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   468
     * @param tokens       command tokens
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   469
     * @param cwd          current working directory
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   470
     * @param redirectInfo redirection information
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   471
     * @return tokens remaining for actual command
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   472
     */
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   473
    private List<String>  preprocessCommand(final List<String> tokens,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   474
            final String cwd, final RedirectInfo redirectInfo) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   475
        // Tokens remaining for actual command.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   476
        final List<String> command = new ArrayList<>();
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   477
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   478
        // iterate through all tokens.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   479
        final Iterator<String> iterator = tokens.iterator();
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   480
        while (iterator.hasNext()) {
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   481
            final String token = iterator.next();
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   482
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   483
            // Check if is a redirect.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   484
            if (redirectInfo.check(token, iterator, cwd)) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   485
                // Don't add to the command.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   486
                continue;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   487
            }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   488
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   489
            // Strip quotes and add to command.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   490
            command.add(stripQuotes(token));
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   491
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   492
36479
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   493
        if (command.size() > 0) {
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   494
            command.set(0, sanitizePath(command.get(0)));
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   495
        }
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   496
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   497
        return command;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   498
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   499
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   500
    /**
36479
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   501
     * Sanitize a path in case the underlying platform is Cygwin. In that case,
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   502
     * convert from the {@code /cygdrive/x} drive specification to the usual
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   503
     * Windows {@code X:} format.
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   504
     *
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   505
     * @param d a String representing a path
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   506
     * @return a String representing the same path in a form that can be
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   507
     *         processed by the underlying platform
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   508
     */
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   509
    private static String sanitizePath(final String d) {
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   510
        if (!IS_WINDOWS || (IS_WINDOWS && !d.startsWith(CYGDRIVE))) {
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   511
            return d;
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   512
        }
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   513
        final String pd = d.substring(CYGDRIVE.length());
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   514
        if (pd.length() >= 2 && pd.charAt(1) == '/') {
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   515
            // drive letter plus / -> convert /cygdrive/x/... to X:/...
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   516
            return pd.charAt(0) + ":" + pd.substring(1);
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   517
        } else if (pd.length() == 1) {
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   518
            // just drive letter -> convert /cygdrive/x to X:
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   519
            return pd.charAt(0) + ":";
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   520
        }
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   521
        // remaining case: /cygdrive/ -> can't convert
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   522
        return d;
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   523
    }
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   524
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   525
    /**
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   526
     * createProcessBuilder - create a ProcessBuilder for the command.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   527
     * @param command      command tokens
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   528
     * @param cwd          current working directory
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   529
     * @param redirectInfo redirect information
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   530
     */
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   531
    private void createProcessBuilder(final List<String> command,
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   532
            final String cwd, final RedirectInfo redirectInfo) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   533
        // Create new ProcessBuilder.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   534
        final ProcessBuilder pb = new ProcessBuilder(command);
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   535
        // Set current working directory.
36479
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   536
        pb.directory(new File(sanitizePath(cwd)));
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   537
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   538
        // Map environment variables.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   539
        final Map<String, String> processEnvironment = pb.environment();
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   540
        processEnvironment.clear();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   541
        processEnvironment.putAll(environment);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   542
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   543
        // Apply redirects.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   544
        redirectInfo.apply(pb);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   545
        // Add to current list of commands.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   546
        processBuilders.add(pb);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   547
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   548
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   549
    /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   550
     * command - process the command
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   551
     * @param tokens  tokens of the command
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   552
     * @param isPiped true if the output of this command should be piped to the next
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   553
     */
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   554
    private void command(final List<String> tokens, final boolean isPiped) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   555
        // Test to see if we should echo the command to output.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   556
        if (envVarBooleanValue("JJS_ECHO")) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   557
            System.out.println(String.join(" ", tokens));
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   558
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   559
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   560
        // Get the current working directory.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   561
        final String cwd = envVarValue("PWD", HOME_DIRECTORY);
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   562
        // Preprocess the command for redirects.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   563
        final RedirectInfo redirectInfo = new RedirectInfo();
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   564
        final List<String> command = preprocessCommand(tokens, cwd, redirectInfo);
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   565
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   566
        // Skip if empty or a built in.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   567
        if (command.isEmpty() || builtIn(command, cwd)) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   568
            return;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   569
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   570
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   571
        // Create ProcessBuilder with cwd and redirects set.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   572
        createProcessBuilder(command, cwd, redirectInfo);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   573
36479
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   574
        // If piped, wait for the next command.
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   575
        if (isPiped) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   576
            return;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   577
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   578
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   579
        // Fetch first and last ProcessBuilder.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   580
        final ProcessBuilder firstProcessBuilder = processBuilders.get(0);
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   581
        final ProcessBuilder lastProcessBuilder = processBuilders.get(processBuilders.size() - 1);
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   582
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   583
        // Determine which streams have not be redirected from pipes.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   584
        boolean inputIsPipe = firstProcessBuilder.redirectInput() == Redirect.PIPE;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   585
        boolean outputIsPipe = lastProcessBuilder.redirectOutput() == Redirect.PIPE;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   586
        boolean errorIsPipe = lastProcessBuilder.redirectError() == Redirect.PIPE;
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   587
        final boolean inheritIO = envVarBooleanValue("JJS_INHERIT_IO");
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   588
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   589
        // If not redirected and inputStream is current processes' input.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   590
        if (inputIsPipe && (inheritIO || inputStream == System.in)) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   591
            // Inherit current processes' input.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   592
            firstProcessBuilder.redirectInput(Redirect.INHERIT);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   593
            inputIsPipe = false;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   594
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   595
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   596
        // If not redirected and outputStream is current processes' output.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   597
        if (outputIsPipe && (inheritIO || outputStream == System.out)) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   598
            // Inherit current processes' output.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   599
            lastProcessBuilder.redirectOutput(Redirect.INHERIT);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   600
            outputIsPipe = false;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   601
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   602
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   603
        // If not redirected and errorStream is current processes' error.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   604
        if (errorIsPipe && (inheritIO || errorStream == System.err)) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   605
            // Inherit current processes' error.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   606
            lastProcessBuilder.redirectError(Redirect.INHERIT);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   607
            errorIsPipe = false;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   608
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   609
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   610
        // Start the processes.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   611
        final List<Process> processes = new ArrayList<>();
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   612
        for (final ProcessBuilder pb : processBuilders) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   613
            try {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   614
                processes.add(pb.start());
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   615
            } catch (final IOException ex) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   616
                reportError("unknown.command", String.join(" ", pb.command()));
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   617
                return;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   618
            }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   619
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   620
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   621
        // Clear processBuilders for next command.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   622
        processBuilders.clear();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   623
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   624
        // Get first and last process.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   625
        final Process firstProcess = processes.get(0);
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   626
        final Process lastProcess = processes.get(processes.size() - 1);
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   627
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   628
        // Prepare for string based i/o if no redirection or provided streams.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   629
        ByteArrayOutputStream byteOutputStream = null;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   630
        ByteArrayOutputStream byteErrorStream = null;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   631
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   632
        final List<Piper> piperThreads = new ArrayList<>();
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   633
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   634
        // If input is not redirected.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   635
        if (inputIsPipe) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   636
            // If inputStream other than System.in is provided.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   637
            if (inputStream != null) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   638
                // Pipe inputStream to first process output stream.
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   639
                piperThreads.add(new Piper(inputStream, firstProcess.getOutputStream()).start());
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   640
            } else {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   641
                // Otherwise assume an input string has been provided.
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   642
                piperThreads.add(new Piper(new ByteArrayInputStream(inputString.getBytes()), firstProcess.getOutputStream()).start());
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   643
            }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   644
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   645
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   646
        // If output is not redirected.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   647
        if (outputIsPipe) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   648
            // If outputStream other than System.out is provided.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   649
            if (outputStream != null ) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   650
                // Pipe outputStream from last process input stream.
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   651
                piperThreads.add(new Piper(lastProcess.getInputStream(), outputStream).start());
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   652
            } else {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   653
                // Otherwise assume an output string needs to be prepared.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   654
                byteOutputStream = new ByteArrayOutputStream(BUFFER_SIZE);
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   655
                piperThreads.add(new Piper(lastProcess.getInputStream(), byteOutputStream).start());
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   656
            }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   657
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   658
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   659
        // If error is not redirected.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   660
        if (errorIsPipe) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   661
            // If errorStream other than System.err is provided.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   662
            if (errorStream != null) {
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   663
                piperThreads.add(new Piper(lastProcess.getErrorStream(), errorStream).start());
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   664
            } else {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   665
                // Otherwise assume an error string needs to be prepared.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   666
                byteErrorStream = new ByteArrayOutputStream(BUFFER_SIZE);
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   667
                piperThreads.add(new Piper(lastProcess.getErrorStream(), byteErrorStream).start());
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   668
            }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   669
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   670
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   671
        // Pipe commands in between.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   672
        for (int i = 0, n = processes.size() - 1; i < n; i++) {
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   673
            final Process prev = processes.get(i);
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   674
            final Process next = processes.get(i + 1);
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   675
            piperThreads.add(new Piper(prev.getInputStream(), next.getOutputStream()).start());
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   676
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   677
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   678
        // Wind up processes.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   679
        try {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   680
            // Get the user specified timeout.
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   681
            final long timeout = envVarLongValue("JJS_TIMEOUT");
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   682
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   683
            // If user specified timeout (milliseconds.)
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   684
            if (timeout != 0) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   685
                // Wait for last process, with timeout.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   686
                if (lastProcess.waitFor(timeout, TimeUnit.MILLISECONDS)) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   687
                    // Get exit code of last process.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   688
                    exitCode = lastProcess.exitValue();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   689
                } else {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   690
                    reportError("timeout", Long.toString(timeout));
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   691
                 }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   692
            } else {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   693
                // Wait for last process and get exit code.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   694
                exitCode = lastProcess.waitFor();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   695
            }
36481
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   696
            // Wait for all piper threads to terminate
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   697
            for (final Piper piper : piperThreads) {
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   698
                piper.join();
9826c19a5310 8151515: $EXEC output is truncated
hannesw
parents: 36479
diff changeset
   699
            }
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   700
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   701
            // Accumulate the output and error streams.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   702
            outputString += byteOutputStream != null ? byteOutputStream.toString() : "";
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   703
            errorString += byteErrorStream != null ? byteErrorStream.toString() : "";
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   704
        } catch (final InterruptedException ex) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   705
            // Kill any living processes.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   706
            processes.stream().forEach(p -> {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   707
                if (p.isAlive()) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   708
                    p.destroy();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   709
                }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   710
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   711
                // Get the first error code.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   712
                exitCode = exitCode == 0 ? p.exitValue() : exitCode;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   713
            });
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   714
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   715
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   716
        // If we got a non-zero exit code then possibly throw an exception.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   717
        if (exitCode != 0 && envVarBooleanValue("JJS_THROW_ON_EXIT")) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   718
            throw rangeError("exec.returned.non.zero", ScriptRuntime.safeToString(exitCode));
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   719
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   720
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   721
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   722
    /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   723
     * createTokenizer - build up StreamTokenizer for the command script
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   724
     * @param script command script to parsed
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   725
     * @return StreamTokenizer for command script
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   726
     */
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   727
    private static StreamTokenizer createTokenizer(final String script) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   728
        final StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(script));
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   729
        tokenizer.resetSyntax();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   730
        // Default all characters to word.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   731
        tokenizer.wordChars(0, 255);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   732
        // Spaces and special characters are white spaces.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   733
        tokenizer.whitespaceChars(0, ' ');
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   734
        // Ignore # comments.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   735
        tokenizer.commentChar('#');
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   736
        // Handle double and single quote strings.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   737
        tokenizer.quoteChar('"');
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   738
        tokenizer.quoteChar('\'');
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   739
        // Need to recognize the end of a command.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   740
        tokenizer.eolIsSignificant(true);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   741
        // Command separator.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   742
        tokenizer.ordinaryChar(';');
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   743
        // Pipe separator.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   744
        tokenizer.ordinaryChar('|');
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   745
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   746
        return tokenizer;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   747
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   748
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   749
    /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   750
     * process - process a command string
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   751
     * @param script command script to parsed
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   752
     */
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   753
    void process(final String script) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   754
        // Build up StreamTokenizer for the command script.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   755
        final StreamTokenizer tokenizer = createTokenizer(script);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   756
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   757
        // Prepare to accumulate command tokens.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   758
        final List<String> command = new ArrayList<>();
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   759
        // Prepare to acumulate partial tokens joined with "\ ".
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   760
        final StringBuilder sb = new StringBuilder();
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   761
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   762
        try {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   763
            // Fetch next token until end of script.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   764
            while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   765
                // Next word token.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   766
                String token = tokenizer.sval;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   767
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   768
                // If special token.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   769
                if (token == null) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   770
                    // Flush any partial token.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   771
                    if (sb.length() != 0) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   772
                        command.add(sb.append(token).toString());
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   773
                        sb.setLength(0);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   774
                    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   775
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   776
                    // Process a completed command.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   777
                    // Will be either ';' (command end) or '|' (pipe), true if '|'.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   778
                    command(command, tokenizer.ttype == '|');
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   779
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   780
                    if (exitCode != EXIT_SUCCESS) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   781
                        return;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   782
                    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   783
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   784
                    // Start with a new set of tokens.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   785
                    command.clear();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   786
                } else if (token.endsWith("\\")) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   787
                    // Backslash followed by space.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   788
                    sb.append(token.substring(0, token.length() - 1)).append(' ');
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   789
                } else if (sb.length() == 0) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   790
                    // If not a word then must be a quoted string.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   791
                    if (tokenizer.ttype != StreamTokenizer.TT_WORD) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   792
                        // Quote string, sb is free to use (empty.)
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   793
                        sb.append((char)tokenizer.ttype);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   794
                        sb.append(token);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   795
                        sb.append((char)tokenizer.ttype);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   796
                        token = sb.toString();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   797
                        sb.setLength(0);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   798
                    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   799
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   800
                    command.add(token);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   801
                } else {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   802
                    // Partial token pending.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   803
                    command.add(sb.append(token).toString());
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   804
                    sb.setLength(0);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   805
                }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   806
            }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   807
        } catch (final IOException ex) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   808
            // Do nothing.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   809
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   810
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   811
        // Partial token pending.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   812
        if (sb.length() != 0) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   813
            command.add(sb.toString());
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   814
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   815
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   816
        // Process last command.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   817
        command(command, false);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   818
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   819
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   820
    /**
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   821
     * process - process a command array of strings
36479
560761a8e879 8151291: $EXEC yields "unknown command" on Cygwin
mhaupt
parents: 35795
diff changeset
   822
     * @param tokens command script to be processed
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   823
     */
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   824
    void process(final List<String> tokens) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   825
        // Prepare to accumulate command tokens.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   826
        final List<String> command = new ArrayList<>();
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   827
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   828
        // Iterate through tokens.
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   829
        final Iterator<String> iterator = tokens.iterator();
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   830
        while (iterator.hasNext() && exitCode == EXIT_SUCCESS) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   831
            // Next word token.
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   832
            final String token = iterator.next();
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   833
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   834
            if (token == null) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   835
                continue;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   836
            }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   837
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   838
            switch (token) {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   839
                case "|":
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   840
                    // Process as a piped command.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   841
                    command(command, true);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   842
                    // Start with a new set of tokens.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   843
                    command.clear();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   844
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   845
                    continue;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   846
                case ";":
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   847
                    // Process as a normal command.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   848
                    command(command, false);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   849
                    // Start with a new set of tokens.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   850
                    command.clear();
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   851
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   852
                    continue;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   853
            }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   854
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   855
            command.add(token);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   856
        }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   857
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   858
        // Process last command.
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   859
        command(command, false);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   860
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   861
35795
5b9049223c34 8149665: $EXEC changes clean up
jlaskey
parents: 35794
diff changeset
   862
    void reportError(final String msg, final String object) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   863
        errorString += ECMAErrors.getMessage("range.error.exec." + msg, object);
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   864
        exitCode = EXIT_FAILURE;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   865
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   866
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   867
    String getOutputString() {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   868
        return outputString;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   869
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   870
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   871
    String getErrorString() {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   872
        return errorString;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   873
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   874
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   875
    int getExitCode() {
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   876
        return exitCode;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   877
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   878
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   879
    void setEnvironment(final Map<String, String> environment) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   880
        this.environment = environment;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   881
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   882
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   883
    void setInputStream(final InputStream inputStream) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   884
        this.inputStream = inputStream;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   885
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   886
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   887
    void setInputString(final String inputString) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   888
        this.inputString = inputString;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   889
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   890
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   891
    void setOutputStream(final OutputStream outputStream) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   892
        this.outputStream = outputStream;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   893
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   894
41422
97eda72f53b6 8167117: insert missing final keywords
attila
parents: 36481
diff changeset
   895
    void setErrorStream(final OutputStream errorStream) {
35794
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   896
        this.errorStream = errorStream;
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   897
    }
049749629dbe 8141209: $EXEC should allow streaming
jlaskey
parents:
diff changeset
   898
}