Here's a patch for Kernel#system that executes ruby scripts in the
current jruby process rather than forking a new JVM and adds support
for the multi-argument variant of Kernel#system. Its based in large
part on a patch provided by Charles.
The new code still fails one of the rubicon tests due to some shell
wildcard expansion differences that I haven't yet figured out.
Marc.
---
Marc Hadley <marc.hadley at sun.com>
Index: RubyKernel.java
*** /Users/mh124079/Development/Ruby/jruby/src/org/jruby/
RubyKernel.java Base (1.45)
--- /Users/mh124079/Development/Ruby/jruby/src/org/jruby/
RubyKernel.java Locally Modified (Based On 1.45)
***************
*** 40,46 ****
--- 40,48 ----
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
+ import java.util.Stack;
import java.util.StringTokenizer;
+ import java.util.Vector;
import java.util.regex.Pattern;
import org.jruby.ast.util.ArgsUtil;
***************
*** 686,692 ****
StringBuffer output = new StringBuffer();
IRuby runtime = recv.getRuntime();
runtime.getGlobalVariables().set("$?", runtime.newFixnum(
! runInShell(runtime, aString.toString(), output)));
return recv.getRuntime().newString(output.toString());
}
--- 688,694 ----
StringBuffer output = new StringBuffer();
IRuby runtime = recv.getRuntime();
runtime.getGlobalVariables().set("$?", runtime.newFixnum(
! runInShell(runtime, new IRubyObject[] {aString},
output)));
return recv.getRuntime().newString(output.toString());
}
***************
*** 745,770 ****
return PATH_SEPARATORS.matcher(executable).replaceAll
(replacement) + remainder;
}
! private static int runInShell(IRuby runtime, String command,
StringBuffer output) {
try {
String shell = System.getProperty("jruby.shell");
! Process aProcess;
! String shellSwitch = "-c";
! command = repairDirSeps(command);
! if (shell != null) {
! if (!shell.endsWith("sh")) {
! shellSwitch = "/c";
}
! aProcess = Runtime.getRuntime().exec(new String[]
{ shell, shellSwitch, command });
} else {
! aProcess = Runtime.getRuntime().exec(command);
}
final BufferedReader reader = new BufferedReader(new
InputStreamReader(aProcess.getInputStream()));
--- 747,845 ----
return PATH_SEPARATORS.matcher(executable).replaceAll
(replacement) + remainder;
}
! private static Vector parseCommandLine(IRubyObject[] rawArgs) {
! // first parse the first element of rawArgs since this may
contain
! // the whole command line
! String command = rawArgs[0].toString();
! Stack args = new Stack();
! StringTokenizer st = new StringTokenizer(command, " ");
! String quoteChar = null;
!
! while (st.hasMoreTokens()) {
! String token = st.nextToken();
! if (quoteChar == null) {
! // not currently in the middle of a quoted token
! if (token.startsWith("'") || token.startsWith("\"")) {
! // note quote char and remove from beginning of
token
! quoteChar = token.substring(0, 1);
! token = token.substring(1);
! }
! if (quoteChar!=null && token.endsWith(quoteChar)) {
! // quoted token self contained, remove from end
of token
! token = token.substring(0, token.length()-1);
! quoteChar = null;
! }
! // add new token to list
! args.push(token);
! } else {
! // in the middle of quoted token
! if (token.endsWith(quoteChar)) {
! // end of quoted token
! token = token.substring(0, token.length()-1);
! quoteChar = null;
! }
! // update token at end of list
! token = args.pop() + " " + token;
! args.push(token);
! }
! }
!
! // now append the remaining raw args to the cooked arg list
! for (int i=1;i<rawArgs.length;i++) {
! args.push(rawArgs[i].toString());
! }
!
! return args;
! }
!
! private static int runInShell(IRuby runtime, IRubyObject[]
rawArgs, StringBuffer output) {
try {
+ // startup scripts set jruby.shell to /bin/sh for Unix,
cmd.exe for Windows
String shell = System.getProperty("jruby.shell");
! Process aProcess = null;
! final Vector args = parseCommandLine(rawArgs);
! String command = (String)args.get(0);
! // this will match ruby anywhere in the path to the
command.
! // it might be better to restrict matches to the final
token after
! // tokenizing with '/'
! if (command.contains("ruby") || command.endsWith(".rb")) {
! // use existing JRuby process to execute command
! Thread t = new Thread() {
! public void run() {
! try {
! String[] argArray = new String[args.size
()-1];
! // snip off ruby or jruby command from
list of arguments
! args.subList(1,args.size()).toArray
(argArray);
! org.jruby.Main.main(argArray);
! } catch (Throwable t) {
}
! }
! };
! t.start();
! t.join();
! } else if (shell != null) {
! // execute command with sh -c or cmd.exe /c
! String shellSwitch = shell.endsWith("sh") ? "-c" :
"/c";
! String[] argArray = new String[3];
! argArray[0] = shell;
! argArray[1] = shellSwitch;
! StringBuffer buf = new StringBuffer();
! for (int i=0;i<args.size();i++) {
! buf.append(args.get(i));
! buf.append(' ');
! }
! argArray[2] = buf.toString();
! aProcess = Runtime.getRuntime().exec(argArray);
} else {
! // execute command directly
! String[] argArray = new String[args.size()];
! args.toArray(argArray);
! aProcess = Runtime.getRuntime().exec(argArray);
}
+ if (aProcess != null) {
final BufferedReader reader = new BufferedReader
(new InputStreamReader(aProcess.getInputStream()));
// Fairly innefficient impl, but readLine is
unable to tell
***************
*** 789,794 ****
--- 867,875 ----
reader.close();
return aProcess.waitFor();
+ } else {
+ return 0;
+ }
} catch (IOException e) {
throw runtime.newIOErrorFromException(e);
} catch (InterruptedException e) {
***************
*** 839,849 ****
public static RubyBoolean system(IRubyObject recv, IRubyObject
[] args) {
IRuby runtime = recv.getRuntime();
- if (args.length > 1) {
- throw runtime.newArgumentError("more arguments not yet
supported");
- }
StringBuffer output = new StringBuffer();
! int resultCode = runInShell(runtime, args[0].toString(),
output);
recv.getRuntime().getGlobalVariables().set("$?",
runtime.newFixnum(resultCode));
return runtime.newBoolean(resultCode == 0);
}
--- 920,928 ----
public static RubyBoolean system(IRubyObject recv, IRubyObject
[] args) {
IRuby runtime = recv.getRuntime();
StringBuffer output = new StringBuffer();
! int resultCode = runInShell(runtime, args, output);
! System.out.println(output.toString());
recv.getRuntime().getGlobalVariables().set("$?",
runtime.newFixnum(resultCode));
return runtime.newBoolean(resultCode == 0);
}
-------------------------------------------------------
This SF.Net email is sponsored by xPML, a groundbreaking scripting language
that extends applications into web and mobile media. Attend the live webcast
and join the prime developer group breaking into this new coding territory!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642
_______________________________________________
Jruby-devel mailing list
Jruby-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jruby-devel