Skip to content

Commit

Permalink
Fixes #1991. Allow launch.inproc=true to expand glob patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
enebo committed Sep 20, 2014
1 parent fb4dc4e commit d3c0106
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 46 deletions.
97 changes: 51 additions & 46 deletions core/src/main/java/org/jruby/util/ShellLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -1048,31 +1050,24 @@ public boolean shouldRunInProcess() {
// and end of each command word and don't run in process if we find them.
for (int i = 0; i < args.length; i++) {
String c = args[i];
if (c.trim().length() == 0) {
continue;
}
if (c.trim().length() == 0) continue;

char[] firstLast = new char[] {c.charAt(0), c.charAt(c.length()-1)};
for (int j = 0; j < firstLast.length; j++) {
switch (firstLast[j]) {
case '<': case '>': case '|': case ';':
case '*': case '?': case '{': case '}':
case '[': case ']': case '(': case ')':
case '~': case '&': case '$': case '"':
case '`': case '\n': case '\\': case '\'':
case '<': case '>': case '|': case ';': case '(': case ')':
case '~': case '&': case '$': case '"': case '`': case '\n':
case '\\': case '\'':
return false;
case '2':
if(c.length() > 1 && c.charAt(1) == '>') {
return false;
}
if(c.length() > 1 && c.charAt(1) == '>') return false;
}
}
}

String command = args[0];

if (Platform.IS_WINDOWS) {
command = command.toLowerCase();
}
if (Platform.IS_WINDOWS) command = command.toLowerCase();

// handle both slash types, \ and /.
String[] slashDelimitedTokens = command.split("[/\\\\]");
Expand All @@ -1082,25 +1077,20 @@ public boolean shouldRunInProcess() {
|| finalToken.endsWith(".rb")
|| finalToken.endsWith("irb"));

if (!inProc) {
return false;
} else {
if (args.length > 1) {
for (int i = 1; i < args.length; i++) {
checkGlobChar(args[i]);
}
}
// snip off ruby or jruby command from list of arguments
// leave alone if the command is the name of a script
int startIndex = command.endsWith(".rb") ? 0 : 1;
if (command.trim().endsWith("irb")) {
startIndex = 0;
args[0] = runtime.getJRubyHome() + File.separator + "bin" + File.separator + "jirb";
}
execArgs = new String[args.length - startIndex];
System.arraycopy(args, startIndex, execArgs, 0, execArgs.length);
return true;
if (!inProc) return false;

// snip off ruby or jruby command from list of arguments
// leave alone if the command is the name of a script
int startIndex = command.endsWith(".rb") ? 0 : 1;
if (command.trim().endsWith("irb")) {
startIndex = 0;
args[0] = runtime.getJRubyHome() + File.separator + "bin" + File.separator + "jirb";
}

execArgs = new String[args.length - startIndex];
System.arraycopy(args, startIndex, execArgs, 0, execArgs.length);

return true;
}

/**
Expand Down Expand Up @@ -1283,17 +1273,6 @@ private static boolean shouldVerifyPathExecutable(String cmdline) {
}
return verifyPathExecutable;
}

private void checkGlobChar(String word) {
if (Options.LAUNCH_INPROC.load() &&
(word.contains("*")
|| word.contains("?")
|| word.contains("[")
|| word.contains("{"))) {
runtime.getErr().println("Warning: treating '" + word + "' literally."
+ " Consider passing -J-Djruby.launch.inproc=false.");
}
}

private Ruby runtime;
private boolean doExecutableSearch;
Expand All @@ -1311,16 +1290,42 @@ public static Process run(Ruby runtime, IRubyObject[] rawArgs, boolean doExecuta
return run(runtime, rawArgs, doExecutableSearch, false);
}

private static boolean hasGlobCharacter(String word) {
return word.contains("*") || word.contains("?") || word.contains("[") || word.contains("{");
}

private static String[] expandGlobs(Ruby runtime, String[] originalArgs) {
List<String> expandedList = new ArrayList<String>(originalArgs.length);
for (int i = 0; i < originalArgs.length; i++) {
if (hasGlobCharacter(originalArgs[i])) {
// FIXME: Encoding lost here
List<ByteList> globs = Dir.push_glob(runtime.getPosix(), runtime.getCurrentDirectory(),
new ByteList(originalArgs[i].getBytes()), 0);

for (ByteList glob: globs) {
expandedList.add(glob.toString());
}
} else {
expandedList.add(originalArgs[i]);
}
}

String[] args = new String[expandedList.size()];
expandedList.toArray(args);

return args;
}

public static Process run(Ruby runtime, IRubyObject[] rawArgs, boolean doExecutableSearch, boolean forceExternalProcess) throws IOException {
Process aProcess = null;
Process aProcess;
File pwd = new File(runtime.getCurrentDirectory());
LaunchConfig cfg = new LaunchConfig(runtime, rawArgs, doExecutableSearch);

try {
if (!forceExternalProcess && cfg.shouldRunInProcess()) {
log(runtime, "Launching in-process");
ScriptThreadProcess ipScript = new ScriptThreadProcess(
runtime, cfg.getExecArgs(), getCurrentEnv(runtime), pwd);
ScriptThreadProcess ipScript = new ScriptThreadProcess(runtime,
expandGlobs(runtime, cfg.getExecArgs()), getCurrentEnv(runtime), pwd);
ipScript.start();
return ipScript;
} else {
Expand Down
5 changes: 5 additions & 0 deletions test/test_command_line_switches.rb
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,11 @@ def test_rubyopts_with_require
ENV['RUBYOPT'] = rubyopt_org
end

def test_inproc_execute_with_globs
args = %{-Xlaunch.inproc=true -e 'system %{jruby -e "p ARGV.sort" test/dir{1,2}/target*}'}
assert_equal %{["test/dir1/target.rb", "test/dir2/target.class"]\n}, jruby(args)
end

# JRUBY-5517
def test_rubyopts_benchmark_cleared_in_child
rubyopt_org = ENV['RUBYOPT']
Expand Down

0 comments on commit d3c0106

Please sign in to comment.