mirror of
https://github.com/mistergibson/gxg-web-client.git
synced 2026-08-15 03:26:00 -07:00
256 lines
7.1 KiB
Ruby
256 lines
7.1 KiB
Ruby
module Rubinius
|
|
class Mirror
|
|
module Process
|
|
def self.set_status_global(status)
|
|
::Thread.current[:$?] = status
|
|
end
|
|
|
|
def self.fork
|
|
Rubinius.primitive :vm_fork
|
|
raise PrimitiveFailure, "Rubinius::Mirror::Process.fork primitive failed"
|
|
end
|
|
|
|
def self.exec(*args)
|
|
exe = Execute.new(*args)
|
|
exe.spawn_setup
|
|
exe.exec exe.command, exe.argv
|
|
end
|
|
|
|
def self.spawn(*args)
|
|
exe = Execute.new(*args)
|
|
|
|
begin
|
|
pid = exe.spawn exe.options, exe.command, exe.argv
|
|
rescue SystemCallError => error
|
|
set_status_global ::Process::Status.new(pid, 127)
|
|
raise error
|
|
end
|
|
|
|
pid
|
|
end
|
|
|
|
def self.backtick(str)
|
|
Rubinius.primitive :vm_backtick
|
|
raise PrimitiveFailure, "Rubinius::Mirror::Process.backtick primitive failed"
|
|
end
|
|
|
|
class Execute
|
|
attr_reader :command
|
|
attr_reader :argv
|
|
attr_reader :options
|
|
|
|
# Turns the various varargs incantations supported by Process.spawn into a
|
|
# [env, prog, argv, redirects, options] tuple.
|
|
#
|
|
# The following method signature is supported:
|
|
# Process.spawn([env], command, ..., [options])
|
|
#
|
|
# The env and options hashes are optional. The command may be a variable
|
|
# number of strings or an Array full of strings that make up the new process's
|
|
# argv.
|
|
#
|
|
# Assigns @environment, @command, @argv, @redirects, @options. All
|
|
# elements are guaranteed to be non-nil. When no env or options are
|
|
# given, empty hashes are returned.
|
|
def initialize(env_or_cmd, *args)
|
|
if options = Rubinius::Type.try_convert(args.last, ::Hash, :to_hash)
|
|
args.pop
|
|
end
|
|
|
|
if env = Rubinius::Type.try_convert(env_or_cmd, ::Hash, :to_hash)
|
|
unless command = args.shift
|
|
raise ArgumentError, "command argument expected"
|
|
end
|
|
else
|
|
command = env_or_cmd
|
|
end
|
|
|
|
if args.empty? and
|
|
cmd = Rubinius::Type.try_convert(command, ::String, :to_str)
|
|
raise Errno::ENOENT if cmd.empty?
|
|
|
|
@command = cmd
|
|
@argv = []
|
|
else
|
|
if cmd = Rubinius::Type.try_convert(command, ::Array, :to_ary)
|
|
raise ArgumentError, "wrong first argument" unless cmd.size == 2
|
|
command = StringValue(cmd[0])
|
|
name = StringValue(cmd[1])
|
|
else
|
|
name = command = StringValue(command)
|
|
end
|
|
|
|
argv = [name]
|
|
args.each { |arg| argv << StringValue(arg) }
|
|
|
|
@command = command
|
|
@argv = argv
|
|
end
|
|
|
|
@options = Rubinius::LookupTable.new if options or env
|
|
|
|
if options
|
|
options.each do |key, value|
|
|
case key
|
|
when ::IO, ::Fixnum, :in, :out, :err
|
|
from = convert_io_fd key
|
|
to = convert_to_fd value, from
|
|
redirect @options, from, to
|
|
when ::Array
|
|
from = convert_io_fd key.first
|
|
to = convert_to_fd value, from
|
|
key.each { |k| redirect @options, convert_io_fd(k), to }
|
|
when :unsetenv_others
|
|
if value
|
|
array = @options[:env] = []
|
|
ENV.each_key { |k| array << convert_env_key(k) << nil }
|
|
end
|
|
when :pgroup
|
|
if value == true
|
|
value = 0
|
|
elsif value
|
|
value = Rubinius::Type.coerce_to value, ::Integer, :to_int
|
|
raise ArgumentError, "negative process group ID : #{value}" if value < 0
|
|
end
|
|
@options[key] = value
|
|
when :chdir
|
|
@options[key] = Rubinius::Type.coerce_to_path(value)
|
|
when :umask
|
|
@options[key] = value
|
|
when :close_others
|
|
@options[key] = value if value
|
|
else
|
|
raise ArgumentError, "unknown exec option: #{key.inspect}"
|
|
end
|
|
end
|
|
end
|
|
|
|
if env
|
|
array = (@options[:env] ||= [])
|
|
|
|
env.each do |key, value|
|
|
array << convert_env_key(key) << convert_env_value(value)
|
|
end
|
|
end
|
|
end
|
|
|
|
private :initialize
|
|
|
|
def redirect(options, from, to)
|
|
case to
|
|
when ::Fixnum
|
|
map = (options[:redirect_fd] ||= [])
|
|
map << from << to
|
|
when ::Array
|
|
map = (options[:assign_fd] ||= [])
|
|
map << from
|
|
map.concat to
|
|
end
|
|
end
|
|
|
|
def convert_io_fd(obj)
|
|
case obj
|
|
when ::Fixnum
|
|
obj
|
|
when :in
|
|
0
|
|
when :out
|
|
1
|
|
when :err
|
|
2
|
|
when ::IO
|
|
obj.fileno
|
|
else
|
|
raise ArgementError, "wrong exec option: #{obj.inspect}"
|
|
end
|
|
end
|
|
|
|
def convert_to_fd(obj, target)
|
|
case obj
|
|
when ::Fixnum
|
|
obj
|
|
when :in
|
|
0
|
|
when :out
|
|
1
|
|
when :err
|
|
2
|
|
when :close
|
|
nil
|
|
when ::IO
|
|
obj.fileno
|
|
when ::String
|
|
[obj, default_mode(target), 0644]
|
|
when ::Array
|
|
case obj.size
|
|
when 1
|
|
[obj[0], File::RDONLY, 0644]
|
|
when 2
|
|
if obj[0] == :child
|
|
convert_to_fd obj[1], target
|
|
else
|
|
[obj[0], convert_file_mode(obj[1]), 0644]
|
|
end
|
|
when 3
|
|
[obj[0], convert_file_mode(obj[1]), obj[2]]
|
|
end
|
|
else
|
|
raise ArgumentError, "wrong exec redirect: #{obj.inspect}"
|
|
end
|
|
end
|
|
|
|
def default_mode(target)
|
|
if target == 1 or target == 2
|
|
OFLAGS["w"]
|
|
else
|
|
OFLAGS["r"]
|
|
end
|
|
end
|
|
|
|
def convert_file_mode(obj)
|
|
case obj
|
|
when ::Fixnum
|
|
obj
|
|
when ::String
|
|
OFLAGS[obj]
|
|
when nil
|
|
OFLAG["r"]
|
|
else
|
|
Rubinius::Type.coerce_to obj, Integer, :to_int
|
|
end
|
|
end
|
|
|
|
def convert_env_key(key)
|
|
key = Rubinius::Type.check_null_safe(StringValue(key))
|
|
|
|
if key.include?("=")
|
|
raise ArgumentError, "environment name contains a equal : #{key}"
|
|
end
|
|
|
|
key
|
|
end
|
|
|
|
def convert_env_value(value)
|
|
return if value.nil?
|
|
Rubinius::Type.check_null_safe(StringValue(value))
|
|
end
|
|
|
|
def spawn_setup
|
|
Rubinius.invoke_primitive :vm_spawn_setup, @options
|
|
end
|
|
|
|
def spawn(exe, command, args)
|
|
Rubinius.primitive :vm_spawn
|
|
raise PrimitiveFailure,
|
|
"Rubinius::Mirror::Process::Execute#spawn primitive failed"
|
|
end
|
|
|
|
def exec(command, args)
|
|
Rubinius.primitive :vm_exec
|
|
raise PrimitiveFailure,
|
|
"Rubinius::Mirror::Process::Execute#exec primitive failed"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|