8080490: add $EXECV command to Nashorn scripting mode
Summary: Additional arguments to the command line can be passed as a single array, or as a sequence of varargs.
Reviewed-by: attila, hannesw
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/samples/exec.js Tue Jun 09 09:27:02 2015 +0200
@@ -0,0 +1,48 @@
+# exec script requires -scripting mode
+
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// The $EXEC builtin function can be used to run external commands:
+$EXEC("ls")
+$EXEC("ls -la")
+
+// It can also be given a string to use as stdin:
+$EXEC("cat", "Hello, world!")
+
+// Additional arguments can be passed after the stdin argument, as an array of
+// strings, or a sequence of varargs:
+$EXEC("ls", "" /* no stdin */, "-l", "-a")
+$EXEC("ls", "" /* no stdin */, ["-l", "-a"])
+
+// Output of running external commands is returned from $EXEC:
+print($EXEC("ls"))
+
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Tue Jun 09 14:19:57 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Tue Jun 09 09:27:02 2015 +0200
@@ -2580,15 +2580,18 @@
final int parameterCount = methodType.parameterCount();
final int callCount = callType.parameterCount();
+ final int pdiff = callCount - parameterCount + 1;
final boolean isCalleeVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray();
- final boolean isCallerVarArg = callerVarArg != null ? callerVarArg.booleanValue() : callCount > 0 &&
+ final boolean isCallerVarArg = callerVarArg != null ? callerVarArg : callCount > 0 &&
callType.parameterType(callCount - 1).isArray();
- if (isCalleeVarArg) {
+ // A value of pdiff < 0 means that there are additional normal arguments in the callee that must not be consumed
+ // by the vararg collector. No vararg collector is required in that case, and no varargs are passed.
+ if (isCalleeVarArg && pdiff >= 0) {
return isCallerVarArg ?
methodHandle :
- MH.asCollector(methodHandle, Object[].class, callCount - parameterCount + 1);
+ MH.asCollector(methodHandle, Object[].class, pdiff);
}
if (isCallerVarArg) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java Tue Jun 09 14:19:57 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java Tue Jun 09 09:27:02 2015 +0200
@@ -41,6 +41,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import jdk.nashorn.internal.objects.NativeArray;
/**
* Global functions supported only in scripting mode.
@@ -54,7 +55,7 @@
public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class);
/** Handle to implementation of {@link ScriptingFunctions#exec} - Nashorn extension */
- public static final MethodHandle EXEC = findOwnMH("exec", Object.class, Object.class, Object.class, Object.class);
+ public static final MethodHandle EXEC = findOwnMH("exec", Object.class, Object.class, Object.class, Object.class, Object[].class);
/** EXEC name - special property used by $EXEC API. */
public static final String EXEC_NAME = "$EXEC";
@@ -128,17 +129,30 @@
* @param self self reference
* @param string string to execute
* @param input input
+ * @param argv additional arguments, to be appended to {@code string}. Additional arguments can be passed as
+ * either one JavaScript array, whose elements will be converted to strings; or as a sequence of
+ * varargs, each of which will be converted to a string.
*
* @return output string from the request
+ *
* @throws IOException if any stream access fails
* @throws InterruptedException if execution is interrupted
*/
- public static Object exec(final Object self, final Object string, final Object input) throws IOException, InterruptedException {
+ public static Object exec(final Object self, final Object string, final Object input, final Object... argv) throws IOException, InterruptedException {
// Current global is need to fetch additional inputs and for additional results.
final ScriptObject global = Context.getGlobal();
+ // Assemble command line, process additional arguments.
+ final List<String> cmdLine = tokenizeString(JSType.toString(string));
+ final Object[] additionalArgs = argv.length == 1 && argv[0] instanceof NativeArray ?
+ ((NativeArray) argv[0]).asObjectArray() :
+ argv;
+ for (Object arg : additionalArgs) {
+ cmdLine.add(JSType.toString(arg));
+ }
+
// Set up initial process.
- final ProcessBuilder processBuilder = new ProcessBuilder(tokenizeString(JSType.toString(string)));
+ final ProcessBuilder processBuilder = new ProcessBuilder(cmdLine);
// Current ENV property state.
final Object env = global.get(ENV_NAME);