aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-06-25 06:42:05 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-06-25 06:42:05 +0000
commit0f0f0f4441e1e8845bf37f6eee712d9f4f73b908 (patch)
tree3e447585929ee787e7ad27c639398ddb0221ec96
parent0e8395d6cb5eb27f0a630be88839e6a11a2ea7c9 (diff)
downloadruby-0f0f0f4441e1e8845bf37f6eee712d9f4f73b908.tar.gz
popen: shell commands with envvar
* io.c (is_popen_fork): check if fork and raise NotImplementedError if unavailable. * io.c (rb_io_s_popen): allow shell commands with modified environment variables. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36213 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog8
-rw-r--r--io.c44
-rw-r--r--test/ruby/test_process.rb49
3 files changed, 63 insertions, 38 deletions
diff --git a/ChangeLog b/ChangeLog
index bc6e53537e..1297c3a3da 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Mon Jun 25 15:42:00 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (is_popen_fork): check if fork and raise NotImplementedError if
+ unavailable.
+
+ * io.c (rb_io_s_popen): allow shell commands with modified environment
+ variables.
+
Mon Jun 25 11:34:45 2012 NAKAMURA Usaku <usa@ruby-lang.org>
* internal.h: use rb_pid_t instead of pid_t because of there is no
diff --git a/io.c b/io.c
index ade1f7bcaa..7798ad5194 100644
--- a/io.c
+++ b/io.c
@@ -5692,35 +5692,30 @@ pipe_open(VALUE execarg_obj, const char *modestr, int fmode, convconfig_t *convc
return port;
}
-static VALUE
-pipe_open_v(int argc, VALUE *argv, const char *modestr, int fmode, convconfig_t *convconfig)
+static int
+is_popen_fork(VALUE prog)
{
- VALUE execarg_obj, ret;
- execarg_obj = rb_execarg_new(argc, argv, FALSE);
- ret = pipe_open(execarg_obj, modestr, fmode, convconfig);
- return ret;
+ if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
+#if !defined(HAVE_FORK)
+ rb_raise(rb_eNotImpError,
+ "fork() function is unimplemented on this machine");
+#else
+ return TRUE;
+#endif
+ }
+ return FALSE;
}
static VALUE
pipe_open_s(VALUE prog, const char *modestr, int fmode, convconfig_t *convconfig)
{
- const char *cmd = RSTRING_PTR(prog);
int argc = 1;
VALUE *argv = &prog;
- VALUE execarg_obj, ret;
+ VALUE execarg_obj = Qnil;
- if (RSTRING_LEN(prog) == 1 && cmd[0] == '-') {
-#if !defined(HAVE_FORK)
- rb_raise(rb_eNotImpError,
- "fork() function is unimplemented on this machine");
-#else
- return pipe_open(Qnil, modestr, fmode, convconfig);
-#endif
- }
-
- execarg_obj = rb_execarg_new(argc, argv, TRUE);
- ret = pipe_open(execarg_obj, modestr, fmode, convconfig);
- return ret;
+ if (!is_popen_fork(prog))
+ execarg_obj = rb_execarg_new(argc, argv, TRUE);
+ return pipe_open(execarg_obj, modestr, fmode, convconfig);
}
/*
@@ -5810,7 +5805,7 @@ static VALUE
rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
{
const char *modestr;
- VALUE pname, pmode, port, tmp, opt;
+ VALUE pname, pmode, port, tmp, opt, execarg_obj;
int oflags, fmode;
convconfig_t convconfig;
@@ -5829,13 +5824,16 @@ rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
#endif
tmp = rb_ary_dup(tmp);
RBASIC(tmp)->klass = 0;
- port = pipe_open_v((int)len, RARRAY_PTR(tmp), modestr, fmode, &convconfig);
+ execarg_obj = rb_execarg_new((int)len, RARRAY_PTR(tmp), TRUE);
rb_ary_clear(tmp);
}
else {
SafeStringValue(pname);
- port = pipe_open_s(pname, modestr, fmode, &convconfig);
+ execarg_obj = Qnil;
+ if (!is_popen_fork(pname))
+ execarg_obj = rb_execarg_new(1, &pname, TRUE);
}
+ port = pipe_open(execarg_obj, modestr, fmode, &convconfig);
if (NIL_P(port)) {
/* child */
if (rb_block_given_p()) {
diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb
index d55496fb05..c7a88b1b49 100644
--- a/test/ruby/test_process.rb
+++ b/test/ruby/test_process.rb
@@ -275,34 +275,53 @@ class TestProcess < Test::Unit::TestCase
assert_equal("PATH\n", io.read)
}
- IO.popen([{"FOO"=>"BAR"}, *ENVCOMMAND]) {|io|
- assert_match(/^FOO=BAR$/, io.read)
- }
-
with_tmpchdir {|d|
system({"fofo"=>"haha"}, *ENVCOMMAND, STDOUT=>"out")
- assert_match(/^fofo=haha$/, File.read("out").chomp)
+ assert_match(/^fofo=haha$/, File.read("out").chomp, message)
+ }
+ end
+
+ def _test_execopts_env_popen(cmd)
+ message = cmd.inspect
+ IO.popen([{"FOO"=>"BAR"}, *cmd]) {|io|
+ assert_match(/^FOO=BAR$/, io.read, message)
}
old = ENV["hmm"]
begin
ENV["hmm"] = "fufu"
- IO.popen(ENVCOMMAND) {|io| assert_match(/^hmm=fufu$/, io.read) }
- IO.popen([{"hmm"=>""}, *ENVCOMMAND]) {|io| assert_match(/^hmm=$/, io.read) }
- IO.popen([{"hmm"=>nil}, *ENVCOMMAND]) {|io| assert_not_match(/^hmm=/, io.read) }
+ IO.popen(cmd) {|io| assert_match(/^hmm=fufu$/, io.read, message)}
+ IO.popen([{"hmm"=>""}, *cmd]) {|io| assert_match(/^hmm=$/, io.read, message)}
+ IO.popen([{"hmm"=>nil}, *cmd]) {|io| assert_not_match(/^hmm=/, io.read, message)}
ENV["hmm"] = ""
- IO.popen(ENVCOMMAND) {|io| assert_match(/^hmm=$/, io.read) }
- IO.popen([{"hmm"=>""}, *ENVCOMMAND]) {|io| assert_match(/^hmm=$/, io.read) }
- IO.popen([{"hmm"=>nil}, *ENVCOMMAND]) {|io| assert_not_match(/^hmm=/, io.read) }
+ IO.popen(cmd) {|io| assert_match(/^hmm=$/, io.read, message)}
+ IO.popen([{"hmm"=>""}, *cmd]) {|io| assert_match(/^hmm=$/, io.read, message)}
+ IO.popen([{"hmm"=>nil}, *cmd]) {|io| assert_not_match(/^hmm=/, io.read, message)}
ENV["hmm"] = nil
- IO.popen(ENVCOMMAND) {|io| assert_not_match(/^hmm=/, io.read) }
- IO.popen([{"hmm"=>""}, *ENVCOMMAND]) {|io| assert_match(/^hmm=$/, io.read) }
- IO.popen([{"hmm"=>nil}, *ENVCOMMAND]) {|io| assert_not_match(/^hmm=/, io.read) }
+ IO.popen(cmd) {|io| assert_not_match(/^hmm=/, io.read, message)}
+ IO.popen([{"hmm"=>""}, *cmd]) {|io| assert_match(/^hmm=$/, io.read, message)}
+ IO.popen([{"hmm"=>nil}, *cmd]) {|io| assert_not_match(/^hmm=/, io.read, message)}
ensure
ENV["hmm"] = old
end
end
+ def test_execopts_env_popen_vector
+ _test_execopts_env_popen(ENVCOMMAND)
+ end
+
+ def test_execopts_env_popen_string
+ with_tmpchdir do |d|
+ open('test-script', 'w') do |f|
+ ENVCOMMAND.each_with_index do |cmd, i|
+ next if i.zero? or cmd == "-e"
+ f.puts cmd
+ end
+ end
+ _test_execopts_env_popen("#{RUBY} test-script")
+ end
+ end
+
def test_execopts_preserve_env_on_exec_failure
with_tmpchdir {|d|
write_file 's', <<-"End"
@@ -603,7 +622,7 @@ class TestProcess < Test::Unit::TestCase
def test_execopts_popen
with_tmpchdir {|d|
IO.popen("#{RUBY} -e 'puts :foo'") {|io| assert_equal("foo\n", io.read) }
- assert_raise(Errno::ENOENT) { IO.popen(["echo bar"]) {} } # assuming "echo bar" command not exist.
+ IO.popen(["echo bar"]) {|io| assert_equal("bar\n", io.read) }
IO.popen(ECHO["baz"]) {|io| assert_equal("baz\n", io.read) }
assert_raise(ArgumentError) {
IO.popen([*ECHO["qux"], STDOUT=>STDOUT]) {|io| }