[DRE-commits] [ruby-posix-spawn] 01/04: Imported Upstream version 0.3.9
Youhei SASAKI
uwabami-guest at moszumanska.debian.org
Wed Oct 1 06:15:32 UTC 2014
This is an automated email from the git hooks/post-receive script.
uwabami-guest pushed a commit to annotated tag debian/0.3.9-1
in repository ruby-posix-spawn.
commit 3aa2a350c51eb600744142c3338f3728d8ab71b2
Author: Youhei SASAKI <uwabami at gfd-dennou.org>
Date: Wed Oct 1 15:01:03 2014 +0900
Imported Upstream version 0.3.9
---
.gitignore | 1 +
Gemfile | 2 +-
README.md | 40 +++++++++++++++++++++++++---
checksums.yaml.gz | Bin 267 -> 269 bytes
ext/posix-spawn.c | 50 +++++++++++++++++++++++++---------
lib/posix/spawn.rb | 38 +++++++++++++++++++-------
lib/posix/spawn/child.rb | 65 ++++++++++++++++++++++++++++++++++++---------
lib/posix/spawn/version.rb | 2 +-
metadata.yml | 15 ++++++-----
posix-spawn.gemspec | 1 +
test/test_backtick.rb | 3 ++-
test/test_child.rb | 43 ++++++++++++++++++++++++++++++
test/test_spawn.rb | 26 +++++++++++-------
13 files changed, 228 insertions(+), 58 deletions(-)
diff --git a/.gitignore b/.gitignore
index e7b4dd5..4633a7f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ ext/Makefile
lib/posix_spawn_ext.*
tmp
pkg
+.bundle
diff --git a/Gemfile b/Gemfile
index e45e65f..851fabc 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,2 +1,2 @@
-source :rubygems
+source 'https://rubygems.org'
gemspec
diff --git a/README.md b/README.md
index a0a9495..cabf1ac 100644
--- a/README.md
+++ b/README.md
@@ -156,9 +156,34 @@ after spawning:
>> child.out
"42\n"
-Additional options can be used to specify the maximum output size and time of
-execution before the child process is aborted. See the `POSIX::Spawn::Child`
-docs for more info.
+Additional options can be used to specify the maximum output size (`:max`) and
+time of execution (`:timeout`) before the child process is aborted. See the
+`POSIX::Spawn::Child` docs for more info.
+
+#### Reading Partial Results
+
+`POSIX::Spawn::Child.new` spawns the process immediately when instantiated.
+As a result, if it is interrupted by an exception (either from reaching the
+maximum output size, the time limit, or another factor), it is not possible to
+access the `out` or `err` results because the constructor did not complete.
+
+If you want to get the `out` and `err` data was available when the process
+was interrupted, use the `POSIX::Spawn::Child.build` alternate form to
+create the child without immediately spawning the process. Call `exec!`
+to run the command at a place where you can catch any exceptions:
+
+ >> child = POSIX::Spawn::Child.build('git', 'log', :max => 100)
+ >> begin
+ ?> child.exec!
+ ?> rescue POSIX::Spawn::MaximumOutputExceeded
+ ?> # limit was reached
+ ?> end
+ >> child.out
+ "commit fa54abe139fd045bf6dc1cc259c0f4c06a9285bb\n..."
+
+Please note that when the `MaximumOutputExceeded` exception is raised, the
+actual combined `out` and `err` data may be a bit longer than the `:max`
+value due to internal buffering.
## STATUS
@@ -180,7 +205,7 @@ These `Process::spawn` arguments are currently supported to any of
:unsetenv_others => true : clear environment variables except specified by env
:unsetenv_others => false : don't clear (default)
current directory:
- :chdir => str
+ :chdir => str : Not thread-safe when using posix_spawn (see below)
process group:
:pgroup => true or 0 : make a new process group
:pgroup => pgid : join to specified process group
@@ -218,6 +243,13 @@ These options are currently NOT supported:
:close_others => false : inherit fds (default for system and exec)
:close_others => true : don't inherit (default for spawn and IO.popen)
+The `:chdir` option provided by Posix::Spawn::Child, Posix::Spawn#spawn,
+Posix::Spawn#system and Posix::Spawn#popen4 is not thread-safe because
+processes spawned with the posix_spawn(2) system call inherit the working
+directory of the calling process. The posix-spawn gem works around this
+limitation in the system call by changing the working directory of the calling
+process immediately before and after spawning the child process.
+
## ACKNOWLEDGEMENTS
Copyright (c) by
diff --git a/checksums.yaml.gz b/checksums.yaml.gz
index 97dc27c..cb2abe4 100644
Binary files a/checksums.yaml.gz and b/checksums.yaml.gz differ
diff --git a/ext/posix-spawn.c b/ext/posix-spawn.c
index 501423d..b6f6fe2 100644
--- a/ext/posix-spawn.c
+++ b/ext/posix-spawn.c
@@ -1,6 +1,6 @@
/* we want GNU extensions like POSIX_SPAWN_USEVFORK */
#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
+#define _GNU_SOURCE 1
#endif
#include <errno.h>
@@ -110,6 +110,13 @@ posixspawn_file_actions_addclose(VALUE key, VALUE val, posix_spawn_file_actions_
fd = posixspawn_obj_to_fd(key);
if (fd >= 0) {
+ /* raise an exception if 'fd' is invalid */
+ if (fcntl(fd, F_GETFD) == -1) {
+ char error_context[32];
+ snprintf(error_context, sizeof(error_context), "when closing fd %d", fd);
+ rb_sys_fail(error_context);
+ return ST_DELETE;
+ }
posix_spawn_file_actions_addclose(fops, fd);
return ST_DELETE;
} else {
@@ -138,6 +145,8 @@ posixspawn_file_actions_adddup2(VALUE key, VALUE val, posix_spawn_file_actions_t
if (fd < 0)
return ST_CONTINUE;
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) & ~FD_CLOEXEC);
+ fcntl(newfd, F_SETFD, fcntl(newfd, F_GETFD) & ~FD_CLOEXEC);
posix_spawn_file_actions_adddup2(fops, fd, newfd);
return ST_DELETE;
}
@@ -319,7 +328,7 @@ each_env_i(VALUE key, VALUE val, VALUE arg)
static VALUE
rb_posixspawn_pspawn(VALUE self, VALUE env, VALUE argv, VALUE options)
{
- int i, ret;
+ int i, ret = 0;
char **envp = NULL;
VALUE dirname;
VALUE cmdname;
@@ -396,9 +405,14 @@ rb_posixspawn_pspawn(VALUE self, VALUE env, VALUE argv, VALUE options)
sigemptyset(&mask);
posix_spawnattr_setsigmask(&attr, &mask);
-#if defined(POSIX_SPAWN_USEVFORK) || defined(__linux__)
- /* Force USEVFORK on linux. If this is undefined, it's probably because
- * you forgot to define _GNU_SOURCE at the top of this file.
+ /* Child reverts SIGPIPE handler to the default. */
+ flags |= POSIX_SPAWN_SETSIGDEF;
+ sigaddset(&mask, SIGPIPE);
+ posix_spawnattr_setsigdefault(&attr, &mask);
+
+#if defined(POSIX_SPAWN_USEVFORK) || defined(__GLIBC__)
+ /* Force USEVFORK on GNU libc. If this is undefined, it's probably
+ * because you forgot to define _GNU_SOURCE at the top of this file.
*/
flags |= POSIX_SPAWN_USEVFORK;
#endif
@@ -411,19 +425,29 @@ rb_posixspawn_pspawn(VALUE self, VALUE env, VALUE argv, VALUE options)
if (RTEST(dirname = rb_hash_delete(options, ID2SYM(rb_intern("chdir"))))) {
char *new_cwd = StringValuePtr(dirname);
cwd = getcwd(NULL, 0);
- chdir(new_cwd);
+ if (chdir(new_cwd) == -1) {
+ free(cwd);
+ cwd = NULL;
+ ret = errno;
+ }
}
- if (RHASH_SIZE(options) == 0) {
- ret = posix_spawnp(&pid, file, &fops, &attr, cargv, envp ? envp : environ);
- if (cwd) {
- chdir(cwd);
- free(cwd);
+ if (ret == 0) {
+ if (RHASH_SIZE(options) == 0) {
+ ret = posix_spawnp(&pid, file, &fops, &attr, cargv, envp ? envp : environ);
+ if (cwd) {
+ /* Ignore chdir failures here. There's already a child running, so
+ * raising an exception here would do more harm than good. */
+ if (chdir(cwd) == -1) {}
+ }
+ } else {
+ ret = -1;
}
- } else {
- ret = -1;
}
+ if (cwd)
+ free(cwd);
+
posix_spawn_file_actions_destroy(&fops);
posix_spawnattr_destroy(&attr);
if (envp) {
diff --git a/lib/posix/spawn.rb b/lib/posix/spawn.rb
index ec19989..dfe0b51 100644
--- a/lib/posix/spawn.rb
+++ b/lib/posix/spawn.rb
@@ -79,7 +79,9 @@ module POSIX
# When a hash is given in the last argument (options), it specifies a
# current directory and zero or more fd redirects for the child process.
#
- # The :chdir option specifies the current directory:
+ # The :chdir option specifies the current directory. Note that :chdir is not
+ # thread-safe on systems that provide posix_spawn(2), because it forces a
+ # temporary change of the working directory of the calling process.
#
# spawn(command, :chdir => "/var/tmp")
#
@@ -210,6 +212,8 @@ module POSIX
if fd?(val)
val = fd_to_io(val)
key.reopen(val)
+ key.close_on_exec = false
+ val.close_on_exec = false
elsif val == :close
if key.respond_to?(:close_on_exec=)
key.close_on_exec = true
@@ -236,7 +240,7 @@ module POSIX
Process::setpgid(0, pgroup) if pgroup
# do the deed
- ::Kernel::exec(*argv)
+ ::Kernel::exec(*argv, :close_others=>false)
ensure
exit!(127)
end
@@ -267,12 +271,7 @@ module POSIX
# Returns the String output of the command.
def `(cmd)
r, w = IO.pipe
- if RUBY_PLATFORM =~ /(mswin|mingw|cygwin|bccwin)/
- sh = ENV['COMSPEC'] || 'cmd.exe'
- pid = spawn([sh, sh], '/c', cmd, :out => w, r => :close)
- else
- pid = spawn(['/bin/sh', '/bin/sh'], '-c', cmd, :out => w, r => :close)
- end
+ pid = spawn(*system_command_prefixes, cmd, :out => w, r => :close)
if pid > 0
w.close
@@ -488,6 +487,27 @@ module POSIX
end
end
+ # Derives the shell command to use when running the spawn.
+ #
+ # On a Windows machine, this will yield:
+ # [['cmd.exe', 'cmd.exe'], '/c']
+ # Note: 'cmd.exe' is used if the COMSPEC environment variable
+ # is not specified. If you would like to use something other
+ # than 'cmd.exe', specify its path in ENV['COMSPEC']
+ #
+ # On all other systems, this will yield:
+ # [['/bin/sh', '/bin/sh'], '-c']
+ #
+ # Returns a platform-specific [[<shell>, <shell>], <command-switch>] array.
+ def system_command_prefixes
+ if RUBY_PLATFORM =~ /(mswin|mingw|cygwin|bccwin)/
+ sh = ENV['COMSPEC'] || 'cmd.exe'
+ [[sh, sh], '/c']
+ else
+ [['/bin/sh', '/bin/sh'], '-c']
+ end
+ end
+
# Converts the various supported command argument variations into a
# standard argv suitable for use with exec. This includes detecting commands
# to be run through the shell (single argument strings with spaces).
@@ -503,7 +523,7 @@ module POSIX
def adjust_process_spawn_argv(args)
if args.size == 1 && args[0] =~ /[ |>]/
# single string with these characters means run it through the shell
- [['/bin/sh', '/bin/sh'], '-c', args[0]]
+ [*system_command_prefixes, args[0]]
elsif !args[0].respond_to?(:to_ary)
# [argv0, argv1, ...]
[[args[0], args[0]], *args[1..-1]]
diff --git a/lib/posix/spawn/child.rb b/lib/posix/spawn/child.rb
index 54fa78c..f310a02 100644
--- a/lib/posix/spawn/child.rb
+++ b/lib/posix/spawn/child.rb
@@ -30,6 +30,17 @@ module POSIX
# >> child.out
# "42\n"
#
+ # To access output from the process even if an exception was raised:
+ #
+ # >> child = POSIX::Spawn::Child.build('git', 'log', :max => 1000)
+ # >> begin
+ # ?> child.exec!
+ # ?> rescue POSIX::Spawn::MaximumOutputExceeded
+ # ?> # just so you know
+ # ?> end
+ # >> child.out
+ # "... first 1000 characters of log output ..."
+ #
# Q: Why use POSIX::Spawn::Child instead of popen3, hand rolled fork/exec
# code, or Process::spawn?
#
@@ -77,7 +88,32 @@ module POSIX
@timeout = @options.delete(:timeout)
@max = @options.delete(:max)
@options.delete(:chdir) if @options[:chdir].nil?
- exec!
+ exec! if !@options.delete(:noexec)
+ end
+
+ # Set up a new process to spawn, but do not actually spawn it.
+ #
+ # Invoke this just like the normal constructor to set up a process
+ # to be run. Call `exec!` to actually run the child process, send
+ # the input, read the output, and wait for completion. Use this
+ # alternative way of constructing a POSIX::Spawn::Child if you want
+ # to read any partial output from the child process even after an
+ # exception.
+ #
+ # child = POSIX::Spawn::Child.build(... arguments ...)
+ # child.exec!
+ #
+ # The arguments are the same as the regular constructor.
+ #
+ # Returns a new Child instance but does not run the underlying process.
+ def self.build(*args)
+ options =
+ if args[-1].respond_to?(:to_hash)
+ args.pop.to_hash
+ else
+ {}
+ end
+ new(*args, { :noexec => true }.merge(options))
end
# All data written to the child process's stdout stream as a String.
@@ -97,15 +133,15 @@ module POSIX
@status && @status.success?
end
- private
# Execute command, write input, and read output. This is called
- # immediately when a new instance of this object is initialized.
+ # immediately when a new instance of this object is created, or
+ # can be called explicitly when creating the Child via `build`.
def exec!
# spawn the process and hook up the pipes
pid, stdin, stdout, stderr = popen4(@env, *(@argv + [@options]))
# async read from all streams into buffers
- @out, @err = read_and_write(@input, stdin, stdout, stderr, @timeout, @max)
+ read_and_write(@input, stdin, stdout, stderr, @timeout, @max)
# grab exit status
@status = waitpid(pid)
@@ -121,6 +157,7 @@ module POSIX
[stdin, stdout, stderr].each { |fd| fd.close rescue nil }
end
+ private
# Maximum buffer size for reading
BUFSIZE = (32 * 1024)
@@ -142,16 +179,16 @@ module POSIX
# exceeds the amount specified by the max argument.
def read_and_write(input, stdin, stdout, stderr, timeout=nil, max=nil)
max = nil if max && max <= 0
- out, err = '', ''
+ @out, @err = '', ''
offset = 0
# force all string and IO encodings to BINARY under 1.9 for now
- if out.respond_to?(:force_encoding) and stdin.respond_to?(:set_encoding)
+ if @out.respond_to?(:force_encoding) and stdin.respond_to?(:set_encoding)
[stdin, stdout, stderr].each do |fd|
fd.set_encoding('BINARY', 'BINARY')
end
- out.force_encoding('BINARY')
- err.force_encoding('BINARY')
+ @out.force_encoding('BINARY')
+ @err.force_encoding('BINARY')
input = input.dup.force_encoding('BINARY') if input
end
@@ -167,7 +204,9 @@ module POSIX
stdin.close
[]
end
+ slice_method = input.respond_to?(:byteslice) ? :byteslice : :slice
t = timeout
+
while readers.any? || writers.any?
ready = IO.select(readers, writers, readers + writers, t)
raise TimeoutExceeded if ready.nil?
@@ -177,11 +216,11 @@ module POSIX
begin
boom = nil
size = fd.write_nonblock(input)
- input = input[size, input.size]
+ input = input.send(slice_method, size..-1)
rescue Errno::EPIPE => boom
rescue Errno::EAGAIN, Errno::EINTR
end
- if boom || input.size == 0
+ if boom || input.bytesize == 0
stdin.close
writers.delete(stdin)
end
@@ -189,7 +228,7 @@ module POSIX
# read from stdout and stderr streams
ready[0].each do |fd|
- buf = (fd == stdout) ? out : err
+ buf = (fd == stdout) ? @out : @err
begin
buf << fd.readpartial(BUFSIZE)
rescue Errno::EAGAIN, Errno::EINTR
@@ -207,12 +246,12 @@ module POSIX
end
# maybe we've hit our max output
- if max && ready[0].any? && (out.size + err.size) > max
+ if max && ready[0].any? && (@out.size + @err.size) > max
raise MaximumOutputExceeded
end
end
- [out, err]
+ [@out, @err]
end
# Wait for the child process to exit
diff --git a/lib/posix/spawn/version.rb b/lib/posix/spawn/version.rb
index c93fb55..c477be8 100644
--- a/lib/posix/spawn/version.rb
+++ b/lib/posix/spawn/version.rb
@@ -1,5 +1,5 @@
module POSIX
module Spawn
- VERSION = '0.3.8'
+ VERSION = '0.3.9'
end
end
diff --git a/metadata.yml b/metadata.yml
index 829ae26..110f18e 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,7 +1,7 @@
--- !ruby/object:Gem::Specification
name: posix-spawn
version: !ruby/object:Gem::Version
- version: 0.3.8
+ version: 0.3.9
platform: ruby
authors:
- Ryan Tomayko
@@ -9,7 +9,7 @@ authors:
autorequire:
bindir: bin
cert_chain: []
-date: 2013-12-06 00:00:00.000000000 Z
+date: 2014-08-01 00:00:00.000000000 Z
dependencies:
- !ruby/object:Gem::Dependency
name: rake-compiler
@@ -37,7 +37,7 @@ extra_rdoc_files:
- COPYING
- HACKING
files:
-- .gitignore
+- ".gitignore"
- COPYING
- Gemfile
- HACKING
@@ -58,7 +58,8 @@ files:
- test/test_spawn.rb
- test/test_system.rb
homepage: http://github.com/rtomayko/posix-spawn
-licenses: []
+licenses:
+- MIT
metadata: {}
post_install_message:
rdoc_options: []
@@ -66,17 +67,17 @@ require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
requirements:
- - - '>='
+ - - ">="
- !ruby/object:Gem::Version
version: '0'
required_rubygems_version: !ruby/object:Gem::Requirement
requirements:
- - - '>='
+ - - ">="
- !ruby/object:Gem::Version
version: '0'
requirements: []
rubyforge_project:
-rubygems_version: 2.0.3
+rubygems_version: 2.2.2
signing_key:
specification_version: 4
summary: posix_spawnp(2) for ruby
diff --git a/posix-spawn.gemspec b/posix-spawn.gemspec
index c42433f..f2e4fbe 100644
--- a/posix-spawn.gemspec
+++ b/posix-spawn.gemspec
@@ -11,6 +11,7 @@ Gem::Specification.new do |s|
s.authors = ['Ryan Tomayko', 'Aman Gupta']
s.email = ['r at tomayko.com', 'aman at tmm1.net']
+ s.license = 'MIT'
s.add_development_dependency 'rake-compiler', '0.7.6'
diff --git a/test/test_backtick.rb b/test/test_backtick.rb
index 93e9559..708b73d 100644
--- a/test/test_backtick.rb
+++ b/test/test_backtick.rb
@@ -24,7 +24,8 @@ class BacktickTest < Test::Unit::TestCase
def test_backtick_redirect
out = `nosuchcmd 2>&1`
- assert_equal "/bin/sh: nosuchcmd: command not found\n", out
+ regex = %r{/bin/sh: (1: )?nosuchcmd: (command )?not found}
+ assert regex.match(out), "Got #{out.inspect}, expected match of pattern #{regex.inspect}"
assert_equal 127, $?.exitstatus, 127
end
diff --git a/test/test_child.rb b/test/test_child.rb
index 912cb0a..f96b1a4 100644
--- a/test/test_child.rb
+++ b/test/test_child.rb
@@ -74,6 +74,23 @@ class ChildTest < Test::Unit::TestCase
end
end
+ def test_max_with_partial_output
+ p = Child.build('yes', :max => 100_000)
+ assert_nil p.out
+ assert_raise MaximumOutputExceeded do
+ p.exec!
+ end
+ assert_output_exceeds_repeated_string("y\n", 100_000, p.out)
+ end
+
+ def test_max_with_partial_output_long_lines
+ p = Child.build('yes', "nice to meet you", :max => 10_000)
+ assert_raise MaximumOutputExceeded do
+ p.exec!
+ end
+ assert_output_exceeds_repeated_string("nice to meet you\n", 10_000, p.out)
+ end
+
def test_timeout
start = Time.now
assert_raise TimeoutExceeded do
@@ -88,6 +105,16 @@ class ChildTest < Test::Unit::TestCase
end
end
+ def test_timeout_with_partial_output
+ start = Time.now
+ p = Child.build('echo Hello; sleep 1', :timeout => 0.05)
+ assert_raise TimeoutExceeded do
+ p.exec!
+ end
+ assert (Time.now-start) <= 0.2
+ assert_equal "Hello\n", p.out
+ end
+
def test_lots_of_input_and_lots_of_output_at_the_same_time
input = "stuff on stdin \n" * 1_000
command = "
@@ -114,4 +141,20 @@ class ChildTest < Test::Unit::TestCase
p = Child.new('cat', :input => input)
assert p.success?
end
+
+ def test_utf8_input_long
+ input = "hålø" * 10_000
+ p = Child.new('cat', :input => input)
+ assert p.success?
+ end
+
+ ##
+ # Assertion Helpers
+
+ def assert_output_exceeds_repeated_string(str, len, actual)
+ assert_operator actual.length, :>=, len
+
+ expected = (str * (len / str.length + 1)).slice(0, len)
+ assert_equal expected, actual.slice(0, len)
+ end
end
diff --git a/test/test_spawn.rb b/test/test_spawn.rb
index ac5b9fb..38bfb3d 100644
--- a/test/test_spawn.rb
+++ b/test/test_spawn.rb
@@ -68,33 +68,33 @@ module SpawnImplementationTests
def test_sanity_of_checking_clone_with_sh
rd, wr = IO.pipe
- pid = _spawn("exec 2>/dev/null 100<&#{rd.posix_fileno} || exit 1", rd => rd)
+ pid = _spawn("exec 2>/dev/null 9<&#{rd.posix_fileno} || exit 1", rd => rd)
assert_process_exit_status pid, 0
ensure
[rd, wr].each { |fd| fd.close rescue nil }
end
def test_spawn_close_option_with_symbolic_standard_stream_names
- pid = _spawn('exec 2>/dev/null 100<&0 || exit 1', :in => :close)
+ pid = _spawn('true 2>/dev/null 9<&0 || exit 1', :in => :close)
assert_process_exit_status pid, 1
- pid = _spawn('exec 2>/dev/null 101>&1 102>&2 || exit 1',
+ pid = _spawn('true 2>/dev/null 9>&1 8>&2 || exit 1',
:out => :close, :err => :close)
assert_process_exit_status pid, 1
end
def test_spawn_close_on_standard_stream_io_object
- pid = _spawn('exec 2>/dev/null 100<&0 || exit 1', STDIN => :close)
+ pid = _spawn('true 2>/dev/null 9<&0 || exit 1', STDIN => :close)
assert_process_exit_status pid, 1
- pid = _spawn('exec 2>/dev/null 101>&1 102>&2 || exit 1',
+ pid = _spawn('true 2>/dev/null 9>&1 8>&2 || exit 1',
STDOUT => :close, STDOUT => :close)
assert_process_exit_status pid, 1
end
def test_spawn_close_option_with_fd_number
rd, wr = IO.pipe
- pid = _spawn("exec 2>/dev/null 100<&#{rd.posix_fileno} || exit 1", rd.posix_fileno => :close)
+ pid = _spawn("true 2>/dev/null 9<&#{rd.posix_fileno} || exit 1", rd.posix_fileno => :close)
assert_process_exit_status pid, 1
assert !rd.closed?
@@ -105,7 +105,7 @@ module SpawnImplementationTests
def test_spawn_close_option_with_io_object
rd, wr = IO.pipe
- pid = _spawn("exec 2>/dev/null 100<&#{rd.posix_fileno} || exit 1", rd => :close)
+ pid = _spawn("true 2>/dev/null 9<&#{rd.posix_fileno} || exit 1", rd => :close)
assert_process_exit_status pid, 1
assert !rd.closed?
@@ -121,9 +121,17 @@ module SpawnImplementationTests
# this happens on darwin only. GNU does spawn and exits 127.
end
+ def test_spawn_invalid_chdir_raises_exception
+ pid = _spawn("echo", "hiya", :chdir => "/this/does/not/exist")
+ # fspawn does chdir in child, so it exits with 127
+ assert_process_exit_status pid, 127
+ rescue Errno::ENOENT
+ # pspawn and native spawn do chdir in parent, so they throw an exception
+ end
+
def test_spawn_closing_multiple_fds_with_array_keys
rd, wr = IO.pipe
- pid = _spawn("exec 2>/dev/null 101>&#{wr.posix_fileno} || exit 1", [rd, wr, :out] => :close)
+ pid = _spawn("true 2>/dev/null 9>&#{wr.posix_fileno} || exit 1", [rd, wr, :out] => :close)
assert_process_exit_status pid, 1
ensure
[rd, wr].each { |fd| fd.close rescue nil }
@@ -181,7 +189,7 @@ module SpawnImplementationTests
# have to pass it explicitly as fd => fd.
def test_explicitly_passing_an_fd_as_open
rd, wr = IO.pipe
- pid = _spawn("exec 101>&#{wr.posix_fileno} || exit 1", wr => wr)
+ pid = _spawn("exec 9>&#{wr.posix_fileno} || exit 1", wr => wr)
assert_process_exit_ok pid
ensure
[rd, wr].each { |fd| fd.close rescue nil }
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-posix-spawn.git
More information about the Pkg-ruby-extras-commits
mailing list