Skip to content

Commit

Permalink
Add reimpl of Kernel#` using Java 7 process APIs.
Browse files Browse the repository at this point in the history
  • Loading branch information
headius committed Jun 16, 2012
1 parent 15dede5 commit c7c7c7d
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 13 deletions.
5 changes: 4 additions & 1 deletion src/jruby/kernel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@

# These are loads so they don't pollute LOADED_FEATURES
load 'jruby/kernel/generator.rb'
load 'jruby/kernel/signal.rb'
load 'jruby/kernel/signal.rb'

# Java 7 process launching support
load 'jruby/kernel/jruby/process_manager.rb' if ENV_JAVA['java.specification.version'] == '1.7'
51 changes: 51 additions & 0 deletions src/jruby/kernel/jruby/process_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
require 'jruby'

module JRuby
# Implementations of key core process-launching methods using Java 7 process
# launching APIs.
module ProcessManager
java_import org.jruby.RubyProcess
java_import org.jruby.util.ShellLauncher
java_import java.lang.ProcessBuilder
java_import org.jruby.runtime.builtin.IRubyObject

Redirect = ProcessBuilder::Redirect
LaunchConfig = ShellLauncher::LaunchConfig
JFile = java.io.File

def self.`(command)
command = command.to_str unless command.kind_of?(String)

config = LaunchConfig.new(JRuby.runtime, [command].to_java(IRubyObject), false)

if config.should_run_in_shell?
config.verify_executable_for_shell
else
config.verifiy_executable_for_direct
end

pb = ProcessBuilder.new(config.exec_args)
pb.redirect_input(Redirect::INHERIT)
pb.environment(ShellLauncher.get_current_env(JRuby.runtime))
pb.directory(JFile.new(JRuby.runtime.current_directory))
process = pb.start

pid = ShellLauncher.reflect_pid_from_process(process)
out = process.input_stream
result = out.to_io.read
exit_value = process.wait_for

status = RubyProcess::RubyStatus.newProcessStatus(JRuby.runtime, exit_value, pid)
JRuby.runtime.current_context.last_exit_status = status

result
end
end
end

module Kernel
module_function
def `(command)
JRuby::ProcessManager.`(command)
end
end
16 changes: 8 additions & 8 deletions src/org/jruby/util/ShellLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ private void closeStreams() {
}
}

private static String[] getCurrentEnv(Ruby runtime) {
public static String[] getCurrentEnv(Ruby runtime) {
return getCurrentEnv(runtime, null);
}

Expand Down Expand Up @@ -977,8 +977,8 @@ private void pumpInerr(Process child, Ruby runtime) {
}
}

private static class LaunchConfig {
LaunchConfig(Ruby runtime, IRubyObject[] rawArgs, boolean doExecutableSearch) {
public static class LaunchConfig {
public LaunchConfig(Ruby runtime, IRubyObject[] rawArgs, boolean doExecutableSearch) {
this.runtime = runtime;
this.rawArgs = rawArgs;
this.doExecutableSearch = doExecutableSearch;
Expand All @@ -990,7 +990,7 @@ private static class LaunchConfig {
* Only run an in-process script if the script name has "ruby", ".rb",
* or "irb" in the name.
*/
private boolean shouldRunInProcess() {
public boolean shouldRunInProcess() {
if (!runtime.getInstanceConfig().isRunRubyInProcess()
|| RubyInstanceConfig.hasLoadedNativeExtensions()) {
return false;
Expand Down Expand Up @@ -1061,7 +1061,7 @@ private boolean shouldRunInProcess() {
* In that case it's better to try passing the bare arguments to runtime.exec.
* On all other platforms we'll always run the command in the shell.
*/
private boolean shouldRunInShell() {
public boolean shouldRunInShell() {
if (rawArgs.length != 1) {
// this is the case when exact executable and its parameters passed,
// in such cases MRI just executes it, without any shell.
Expand Down Expand Up @@ -1109,7 +1109,7 @@ private boolean shouldRunInShell() {
return false;
}

private void verifyExecutableForShell() {
public void verifyExecutableForShell() {
String cmdline = rawArgs[0].toString().trim();
if (doExecutableSearch && shouldVerifyPathExecutable(cmdline) && !cmdBuiltin) {
verifyExecutable();
Expand All @@ -1129,7 +1129,7 @@ private void verifyExecutableForShell() {
}
}

private void verifyExecutableForDirect() {
public void verifyExecutableForDirect() {
verifyExecutable();
execArgs = args;
try {
Expand All @@ -1151,7 +1151,7 @@ private void verifyExecutable() {
}
}

private String[] getExecArgs() {
public String[] getExecArgs() {
return execArgs;
}

Expand Down
2 changes: 1 addition & 1 deletion test/org/jruby/embed/ScriptingContainerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1486,7 +1486,7 @@ public void testMethods() {
"equals__method", "equals__method?", "extend", "finalize", "finalize__method",
"find", "find_all", "find_index", "first", "freeze", "frozen?", "get",
"getClass", "getClass__method", "get__method", "get_class", "get_class__method",
"grep", "group_by", "handle_different_imports", "hash", "hashCode",
"grep", "group_by", "hash", "hashCode",
"hashCode__method", "hash_code", "hash_code__method", "id", "include?",
"java_import", "initialize", "inject", "inspect", "instance_eval",
"instance_exec", "instance_of?", "instance_variable_defined?",
Expand Down
11 changes: 9 additions & 2 deletions test/org/jruby/test/TestUnitTestSuite.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyInstanceConfig;
import org.jruby.exceptions.RaiseException;

/**
Expand Down Expand Up @@ -97,13 +98,19 @@ public Interpreter() {
err = new ByteArrayOutputStream();
printOut = new PrintStream(out);
printErr = new PrintStream(err);
runtime = Ruby.newInstance(in, printOut, printErr);
RubyInstanceConfig config = new RubyInstanceConfig();
ArrayList loadPath = new ArrayList();

loadPath.add("test/externals/bfts");
loadPath.add("test/externals/ruby_test/lib");
config.setLoadPaths(loadPath);
config.setInput(in);
config.setOutput(printOut);
config.setError(printErr);

runtime.getLoadService().init(loadPath);
runtime = Ruby.newInstance(config);

// clear ARGV
runtime.defineGlobalConstant("ARGV", runtime.newArray());
}

Expand Down
24 changes: 23 additions & 1 deletion test/test_object_class_default_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,31 @@ class TestObjectClassDefaultMethods < Test::Unit::TestCase
untaint
)

JAVA_METHODS = %w(
method_added
handle_different_imports
include_class
java_kind_of?
java_signature
com
to_java
java_annotation
org
java_implements
java
java_package
java_name
java_require
javax
)

def test_no_rogue_methods_on_object_class
rogue_methods = Object.methods - METHODS
# reject Java methods, since we have started loading it for core functionality
rogue_methods -= JAVA_METHODS

rogue_methods.reject!{|m| m =~ /^__.+__$/}
assert rogue_methods.empty?

assert rogue_methods.empty?, "Rogue methods found: #{rogue_methods.inspect}"
end
end

0 comments on commit c7c7c7d

Please sign in to comment.