8080490: add $EXECV command to Nashorn scripting mode
authormhaupt
Tue, 09 Jun 2015 09:27:02 +0200
changeset 31099 c5dcfe771907
parent 31098 e98a3ba5d5da
child 31100 4f7ba6a0bb37
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
nashorn/samples/exec.js
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java
--- /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);