open4 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,110 @@
1
+ URIS
2
+
3
+ http://rubyforge.org/frs/?group_id=1024
4
+ http://www.codeforpeople.com/lib/ruby/
5
+
6
+
7
+ SYNOPSIS
8
+
9
+ open child process with handles on pid, stdin, stdout, and stderr
10
+
11
+
12
+ HISTORY
13
+
14
+ 0.2.0 :
15
+ - added exception marshaled from child -> parent when exec fails. thanks
16
+ to jordan breeding for a patch (yay!) and paul brannan for this most
17
+ excellent idea.
18
+
19
+ 0.1.0 :
20
+ - fixed docs to correctly show return value of popen4 (pid first not last).
21
+ thanks Stefanie Tellex <stefie10@alum.mit.edu> for catching this.
22
+ 0.0.0 :
23
+ - initial version
24
+
25
+
26
+ INSTALL
27
+
28
+ ~> gem install open4
29
+
30
+
31
+ SAMPLES
32
+
33
+ simple usage:
34
+
35
+ jib:~/eg/ruby/open4/open4-0.2.0 > cat sample/simple.rb
36
+ require "open4"
37
+
38
+ pid, stdin, stdout, stderr = Open4::popen4 "sh"
39
+
40
+ stdin.puts "echo 42.out"
41
+ stdin.puts "echo 42.err 1>&2"
42
+ stdin.close
43
+
44
+ ignored, status = Process::waitpid2 pid
45
+
46
+ puts "pid : #{ pid }"
47
+ puts "stdout : #{ stdout.read.strip }"
48
+ puts "stderr : #{ stderr.read.strip }"
49
+ puts "status : #{ status.inspect }"
50
+ puts "exitstatus : #{ status.exitstatus }"
51
+
52
+
53
+ jib:~/eg/ruby/open4/open4-0.2.0 > ruby sample/simple.rb
54
+ pid : 17273
55
+ stdout : 42.out
56
+ stderr : 42.err
57
+ status : #<Process::Status: pid=17273,exited(0)>
58
+ exitstatus : 0
59
+
60
+
61
+ block form - child process is automatically waited for:
62
+
63
+
64
+ jib:~/eg/ruby/open4/open4-0.2.0 > cat sample/block.rb
65
+ require 'open4'
66
+
67
+ status =
68
+ Open4::popen4("sh") do |pid, stdin, stdout, stderr|
69
+ stdin.puts "echo 42.out"
70
+ stdin.puts "echo 42.err 1>&2"
71
+ stdin.close
72
+
73
+ puts "pid : #{ pid }"
74
+ puts "stdout : #{ stdout.read.strip }"
75
+ puts "stderr : #{ stderr.read.strip }"
76
+ end
77
+
78
+ puts "status : #{ status.inspect }"
79
+ puts "exitstatus : #{ status.exitstatus }"
80
+
81
+
82
+ jib:~/eg/ruby/open4/open4-0.2.0 > ruby sample/block.rb
83
+ pid : 17295
84
+ stdout : 42.out
85
+ stderr : 42.err
86
+ status : #<Process::Status: pid=17295,exited(0)>
87
+ exitstatus : 0
88
+
89
+
90
+ exceptions are marshaled from child to parent if fork/exec fails:
91
+
92
+
93
+ jib:~/eg/ruby/open4/open4-0.2.0 > cat sample/exception.rb
94
+ require "open4"
95
+ Open4::popen4 "noexist"
96
+
97
+
98
+ jib:~/eg/ruby/open4/open4-0.2.0 > ruby sample/exception.rb
99
+ /dmsp/reference/ruby-1.8.1//lib/ruby/site_ruby/open4.rb:100:in `popen4': No such file or directory - noexist (Errno::ENOENT)
100
+ from sample/exception.rb:3
101
+
102
+
103
+ AUTHOR
104
+
105
+ ara.t.howard@noaa.gov
106
+
107
+
108
+ LICENSE
109
+
110
+ ruby's
data/gemspec.rb ADDED
@@ -0,0 +1,23 @@
1
+ lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2
2
+
3
+ require 'rubygems'
4
+
5
+ Gem::Specification::new do |spec|
6
+ spec.name = lib
7
+ spec.version = version
8
+ spec.platform = Gem::Platform::RUBY
9
+ spec.summary = lib
10
+
11
+ # spec.files = Dir[ File::join("{lib,bin}", "*") ]
12
+ # spec.require_path = "lib"
13
+
14
+ spec.files = Dir::glob "**/**"
15
+ spec.executables = Dir::glob("bin/*").map{|exe| File::basename exe}
16
+
17
+ spec.has_rdoc = File::exist? "doc"
18
+ spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
19
+
20
+ spec.author = "Ara T. Howard"
21
+ spec.email = "ara.t.howard@noaa.gov"
22
+ spec.homepage = "http://codeforpeople.com/lib/ruby/#{ lib }/"
23
+ end
data/install ADDED
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rbconfig'
3
+ require 'find'
4
+ require 'ftools'
5
+ require 'tempfile'
6
+ include Config
7
+
8
+ LIBDIR = "lib"
9
+ LIBDIR_MODE = 0644
10
+
11
+ BINDIR = "bin"
12
+ BINDIR_MODE = 0755
13
+
14
+
15
+ $srcdir = CONFIG["srcdir"]
16
+ $version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
17
+ $libdir = File.join(CONFIG["libdir"], "ruby", $version)
18
+ $archdir = File.join($libdir, CONFIG["arch"])
19
+ $site_libdir = $:.find {|x| x =~ /site_ruby$/}
20
+ $bindir = CONFIG["bindir"] || CONFIG['BINDIR']
21
+ $ruby_install_name = CONFIG['ruby_install_name'] || CONFIG['RUBY_INSTALL_NAME'] || 'ruby'
22
+ $ruby_ext = CONFIG['EXEEXT'] || ''
23
+ $ruby = File.join($bindir, ($ruby_install_name + $ruby_ext))
24
+
25
+ if !$site_libdir
26
+ $site_libdir = File.join($libdir, "site_ruby")
27
+ elsif $site_libdir !~ %r/#{Regexp.quote($version)}/
28
+ $site_libdir = File.join($site_libdir, $version)
29
+ end
30
+
31
+ def install_rb(srcdir=nil, destdir=nil, mode=nil, bin=nil)
32
+ #{{{
33
+ path = []
34
+ dir = []
35
+ Find.find(srcdir) do |f|
36
+ next unless FileTest.file?(f)
37
+ next if (f = f[srcdir.length+1..-1]) == nil
38
+ next if (/CVS$/ =~ File.dirname(f))
39
+ next if f =~ %r/\.lnk/
40
+ path.push f
41
+ dir |= [File.dirname(f)]
42
+ end
43
+ for f in dir
44
+ next if f == "."
45
+ next if f == "CVS"
46
+ File::makedirs(File.join(destdir, f))
47
+ end
48
+ for f in path
49
+ next if (/\~$/ =~ f)
50
+ next if (/^\./ =~ File.basename(f))
51
+ unless bin
52
+ File::install(File.join(srcdir, f), File.join(destdir, f), mode, true)
53
+ else
54
+ from = File.join(srcdir, f)
55
+ to = File.join(destdir, f)
56
+ shebangify(from) do |sf|
57
+ $deferr.print from, " -> ", File::catname(from, to), "\n"
58
+ $deferr.printf "chmod %04o %s\n", mode, to
59
+ File::install(sf, to, mode, false)
60
+ end
61
+ end
62
+ end
63
+ #}}}
64
+ end
65
+ def shebangify f
66
+ #{{{
67
+ open(f) do |fd|
68
+ buf = fd.read 42
69
+ if buf =~ %r/^\s*#\s*!.*ruby/o
70
+ ftmp = Tempfile::new("#{ $$ }_#{ File::basename(f) }")
71
+ begin
72
+ fd.rewind
73
+ ftmp.puts "#!#{ $ruby }"
74
+ while((buf = fd.read(8192)))
75
+ ftmp.write buf
76
+ end
77
+ ftmp.close
78
+ yield ftmp.path
79
+ ensure
80
+ ftmp.close!
81
+ end
82
+ else
83
+ yield f
84
+ end
85
+ end
86
+ #}}}
87
+ end
88
+ def ARGV.switch
89
+ #{{{
90
+ return nil if self.empty?
91
+ arg = self.shift
92
+ return nil if arg == '--'
93
+ if arg =~ /^-(.)(.*)/
94
+ return arg if $1 == '-'
95
+ raise 'unknown switch "-"' if $2.index('-')
96
+ self.unshift "-#{$2}" if $2.size > 0
97
+ "-#{$1}"
98
+ else
99
+ self.unshift arg
100
+ nil
101
+ end
102
+ #}}}
103
+ end
104
+ def ARGV.req_arg
105
+ #{{{
106
+ self.shift || raise('missing argument')
107
+ #}}}
108
+ end
109
+ def linkify d, linked = []
110
+ #--{{{
111
+ if test ?d, d
112
+ versioned = Dir[ File::join(d, "*-[0-9].[0-9].[0-9].rb") ]
113
+ versioned.each do |v|
114
+ src, dst = v, v.gsub(%r/\-[\d\.]+\.rb$/, '.rb')
115
+ lnk = nil
116
+ begin
117
+ if test ?l, dst
118
+ lnk = "#{ dst }.lnk"
119
+ puts "#{ dst } -> #{ lnk }"
120
+ File::rename dst, lnk
121
+ end
122
+ unless test ?e, dst
123
+ puts "#{ src } -> #{ dst }"
124
+ File::copy src, dst
125
+ linked << dst
126
+ end
127
+ ensure
128
+ if lnk
129
+ at_exit do
130
+ puts "#{ lnk } -> #{ dst }"
131
+ File::rename lnk, dst
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ linked
138
+ #--}}}
139
+ end
140
+
141
+
142
+ #
143
+ # main program
144
+ #
145
+
146
+ libdir = $site_libdir
147
+ bindir = $bindir
148
+ no_linkify = false
149
+ linked = nil
150
+ help = false
151
+
152
+ usage = <<-usage
153
+ #{ File::basename $0 }
154
+ -d, --destdir <destdir>
155
+ -l, --libdir <libdir>
156
+ -b, --bindir <bindir>
157
+ -r, --ruby <ruby>
158
+ -n, --no_linkify
159
+ -h, --help
160
+ usage
161
+
162
+ begin
163
+ while switch = ARGV.switch
164
+ case switch
165
+ when '-d', '--destdir'
166
+ libdir = ARGV.req_arg
167
+ when '-l', '--libdir'
168
+ libdir = ARGV.req_arg
169
+ when '-b', '--bindir'
170
+ bindir = ARGV.req_arg
171
+ when '-r', '--ruby'
172
+ $ruby = ARGV.req_arg
173
+ when '-n', '--no_linkify'
174
+ no_linkify = true
175
+ when '-h', '--help'
176
+ help = true
177
+ else
178
+ raise "unknown switch #{switch.dump}"
179
+ end
180
+ end
181
+ rescue
182
+ STDERR.puts $!.to_s
183
+ STDERR.puts usage
184
+ exit 1
185
+ end
186
+
187
+ if help
188
+ STDOUT.puts usage
189
+ exit
190
+ end
191
+
192
+ unless no_linkify
193
+ linked = linkify('lib') + linkify('bin')
194
+ end
195
+
196
+ install_rb(LIBDIR, libdir, LIBDIR_MODE)
197
+ install_rb(BINDIR, bindir, BINDIR_MODE, bin=true)
198
+
199
+ if linked
200
+ linked.each{|path| File::rm_f path}
201
+ end
data/install.rb ADDED
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rbconfig'
3
+ require 'find'
4
+ require 'ftools'
5
+ require 'tempfile'
6
+ include Config
7
+
8
+ LIBDIR = "lib"
9
+ LIBDIR_MODE = 0644
10
+
11
+ BINDIR = "bin"
12
+ BINDIR_MODE = 0755
13
+
14
+
15
+ $srcdir = CONFIG["srcdir"]
16
+ $version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
17
+ $libdir = File.join(CONFIG["libdir"], "ruby", $version)
18
+ $archdir = File.join($libdir, CONFIG["arch"])
19
+ $site_libdir = $:.find {|x| x =~ /site_ruby$/}
20
+ $bindir = CONFIG["bindir"] || CONFIG['BINDIR']
21
+ $ruby_install_name = CONFIG['ruby_install_name'] || CONFIG['RUBY_INSTALL_NAME'] || 'ruby'
22
+ $ruby_ext = CONFIG['EXEEXT'] || ''
23
+ $ruby = File.join($bindir, ($ruby_install_name + $ruby_ext))
24
+
25
+ if !$site_libdir
26
+ $site_libdir = File.join($libdir, "site_ruby")
27
+ elsif $site_libdir !~ %r/#{Regexp.quote($version)}/
28
+ $site_libdir = File.join($site_libdir, $version)
29
+ end
30
+
31
+ def install_rb(srcdir=nil, destdir=nil, mode=nil, bin=nil)
32
+ #{{{
33
+ path = []
34
+ dir = []
35
+ Find.find(srcdir) do |f|
36
+ next unless FileTest.file?(f)
37
+ next if (f = f[srcdir.length+1..-1]) == nil
38
+ next if (/CVS$/ =~ File.dirname(f))
39
+ next if f =~ %r/\.lnk/
40
+ path.push f
41
+ dir |= [File.dirname(f)]
42
+ end
43
+ for f in dir
44
+ next if f == "."
45
+ next if f == "CVS"
46
+ File::makedirs(File.join(destdir, f))
47
+ end
48
+ for f in path
49
+ next if (/\~$/ =~ f)
50
+ next if (/^\./ =~ File.basename(f))
51
+ unless bin
52
+ File::install(File.join(srcdir, f), File.join(destdir, f), mode, true)
53
+ else
54
+ from = File.join(srcdir, f)
55
+ to = File.join(destdir, f)
56
+ shebangify(from) do |sf|
57
+ $deferr.print from, " -> ", File::catname(from, to), "\n"
58
+ $deferr.printf "chmod %04o %s\n", mode, to
59
+ File::install(sf, to, mode, false)
60
+ end
61
+ end
62
+ end
63
+ #}}}
64
+ end
65
+ def shebangify f
66
+ #{{{
67
+ open(f) do |fd|
68
+ buf = fd.read 42
69
+ if buf =~ %r/^\s*#\s*!.*ruby/o
70
+ ftmp = Tempfile::new("#{ $$ }_#{ File::basename(f) }")
71
+ begin
72
+ fd.rewind
73
+ ftmp.puts "#!#{ $ruby }"
74
+ while((buf = fd.read(8192)))
75
+ ftmp.write buf
76
+ end
77
+ ftmp.close
78
+ yield ftmp.path
79
+ ensure
80
+ ftmp.close!
81
+ end
82
+ else
83
+ yield f
84
+ end
85
+ end
86
+ #}}}
87
+ end
88
+ def ARGV.switch
89
+ #{{{
90
+ return nil if self.empty?
91
+ arg = self.shift
92
+ return nil if arg == '--'
93
+ if arg =~ /^-(.)(.*)/
94
+ return arg if $1 == '-'
95
+ raise 'unknown switch "-"' if $2.index('-')
96
+ self.unshift "-#{$2}" if $2.size > 0
97
+ "-#{$1}"
98
+ else
99
+ self.unshift arg
100
+ nil
101
+ end
102
+ #}}}
103
+ end
104
+ def ARGV.req_arg
105
+ #{{{
106
+ self.shift || raise('missing argument')
107
+ #}}}
108
+ end
109
+ def linkify d, linked = []
110
+ #--{{{
111
+ if test ?d, d
112
+ versioned = Dir[ File::join(d, "*-[0-9].[0-9].[0-9].rb") ]
113
+ versioned.each do |v|
114
+ src, dst = v, v.gsub(%r/\-[\d\.]+\.rb$/, '.rb')
115
+ lnk = nil
116
+ begin
117
+ if test ?l, dst
118
+ lnk = "#{ dst }.lnk"
119
+ puts "#{ dst } -> #{ lnk }"
120
+ File::rename dst, lnk
121
+ end
122
+ unless test ?e, dst
123
+ puts "#{ src } -> #{ dst }"
124
+ File::copy src, dst
125
+ linked << dst
126
+ end
127
+ ensure
128
+ if lnk
129
+ at_exit do
130
+ puts "#{ lnk } -> #{ dst }"
131
+ File::rename lnk, dst
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ linked
138
+ #--}}}
139
+ end
140
+
141
+
142
+ #
143
+ # main program
144
+ #
145
+
146
+ libdir = $site_libdir
147
+ bindir = $bindir
148
+ no_linkify = false
149
+ linked = nil
150
+ help = false
151
+
152
+ usage = <<-usage
153
+ #{ File::basename $0 }
154
+ -d, --destdir <destdir>
155
+ -l, --libdir <libdir>
156
+ -b, --bindir <bindir>
157
+ -r, --ruby <ruby>
158
+ -n, --no_linkify
159
+ -h, --help
160
+ usage
161
+
162
+ begin
163
+ while switch = ARGV.switch
164
+ case switch
165
+ when '-d', '--destdir'
166
+ libdir = ARGV.req_arg
167
+ when '-l', '--libdir'
168
+ libdir = ARGV.req_arg
169
+ when '-b', '--bindir'
170
+ bindir = ARGV.req_arg
171
+ when '-r', '--ruby'
172
+ $ruby = ARGV.req_arg
173
+ when '-n', '--no_linkify'
174
+ no_linkify = true
175
+ when '-h', '--help'
176
+ help = true
177
+ else
178
+ raise "unknown switch #{switch.dump}"
179
+ end
180
+ end
181
+ rescue
182
+ STDERR.puts $!.to_s
183
+ STDERR.puts usage
184
+ exit 1
185
+ end
186
+
187
+ if help
188
+ STDOUT.puts usage
189
+ exit
190
+ end
191
+
192
+ unless no_linkify
193
+ linked = linkify('lib') + linkify('bin')
194
+ end
195
+
196
+ install_rb(LIBDIR, libdir, LIBDIR_MODE)
197
+ install_rb(BINDIR, bindir, BINDIR_MODE, bin=true)
198
+
199
+ if linked
200
+ linked.each{|path| File::rm_f path}
201
+ end
@@ -0,0 +1,131 @@
1
+ # vim: ts=2 sts=2 et
2
+ # stolen directly from Open3::open3.rb!
3
+ #
4
+ # open4.rb: Spawn a program like popen, but with stderr, and pid, too. You might
5
+ # also want to use this if you want to bypass the shell. (By passing multiple
6
+ # args, which IO#popen does not allow)
7
+ #
8
+ # Usage:
9
+ # require "open4"
10
+ #
11
+ # pid, stdin, stdout, stderr = Open4.popen4('nroff -man')
12
+ # or
13
+ # include Open4
14
+ # pid, stdin, stdout, stderr = popen4('nroff -man')
15
+
16
+ require 'fcntl'
17
+
18
+ module Open4
19
+ #--{{{
20
+
21
+ if false
22
+ PROCESSES = Hash.new
23
+
24
+ orig_sigchld_handler = trap("CLD") do |*args|
25
+ begin
26
+ PROCESSES.each do |pid, foo|
27
+ if (Process.waitpid2(pid, Process::WNOHANG) == pid)
28
+ PROCESSES.delete(pid)
29
+ end
30
+ end
31
+ rescue Errno::ECHILD
32
+ nil
33
+ end
34
+ orig_sigchld_handler.call(*args) if (not (orig_sigchld_handler.nil?))
35
+ end
36
+ end
37
+
38
+ #
39
+ # [ pid, stdin, stdout, stderr ] = popen4 command
40
+ #
41
+
42
+ def popen4(*cmd)
43
+ #--{{{
44
+
45
+ pw = IO::pipe # pipe[1] for read, pipe[0] for write
46
+ pr = IO::pipe # pipe[0] for read, pipe[1] for write
47
+ pe = IO::pipe # pipe[0] for read, pipe[1] for write
48
+ ps = IO::pipe # pipe[0] for read, pipe[1] for write
49
+
50
+ verbose = $VERBOSE
51
+ begin
52
+ $VERBOSE = nil # shut up warning about forking in threads, world writable
53
+ # dirs, etc
54
+
55
+ ps[1].fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
56
+
57
+ cid = fork {
58
+ # child
59
+ pw[1].close
60
+ STDIN.reopen(pw[0])
61
+ pw[0].close
62
+
63
+ pr[0].close
64
+ STDOUT.reopen(pr[1])
65
+ pr[1].close
66
+
67
+ pe[0].close
68
+ STDERR.reopen(pe[1])
69
+ pe[1].close
70
+
71
+ STDOUT.sync = true
72
+ STDERR.sync = true
73
+
74
+ begin
75
+ exec(*cmd)
76
+ raise "exec returned!"
77
+ rescue Exception
78
+ Marshal.dump($!, ps[1])
79
+ ps[1].flush
80
+ end
81
+ ps[1].close unless (ps[1].closed?)
82
+ exit!
83
+ }
84
+ ensure
85
+ $VERBOSE = verbose
86
+ end
87
+
88
+ pw[0].close
89
+ pr[1].close
90
+ pe[1].close
91
+ ps[1].close
92
+
93
+ exc = nil
94
+ begin
95
+ exc = Marshal.load(ps[0])
96
+ rescue EOFError # If we get an EOF error, then the exec was successful
97
+ end
98
+
99
+ if (not (exc.nil?)) then
100
+ raise exc
101
+ end
102
+
103
+ # PROCESSES[cid] = true
104
+
105
+ pi = [pw[1], pr[0], pe[0]]
106
+ pw[1].sync = true
107
+ if defined? yield
108
+ begin
109
+ yield(cid, *pi)
110
+ return((Process.waitpid2(cid, 1)).last)
111
+ ensure
112
+ pi.each{|p| p.close unless p.closed?}
113
+ end
114
+ end
115
+ [cid, pw[1], pr[0], pe[0]]
116
+ #--}}}
117
+ end
118
+
119
+ alias open4 popen4
120
+ module_function :popen4
121
+ module_function :open4
122
+
123
+ #--}}}
124
+ end
125
+
126
+ if $0 == __FILE__
127
+ status = Open4::popen4('sh'){|cid,i,o,e|i.puts 'echo 42';i.close; puts o.read;}
128
+ p [status]
129
+ p status.exitstatus
130
+ p status == 0
131
+ end
data/lib/open4.rb ADDED
@@ -0,0 +1,131 @@
1
+ # vim: ts=2 sts=2 et
2
+ # stolen directly from Open3::open3.rb!
3
+ #
4
+ # open4.rb: Spawn a program like popen, but with stderr, and pid, too. You might
5
+ # also want to use this if you want to bypass the shell. (By passing multiple
6
+ # args, which IO#popen does not allow)
7
+ #
8
+ # Usage:
9
+ # require "open4"
10
+ #
11
+ # pid, stdin, stdout, stderr = Open4.popen4('nroff -man')
12
+ # or
13
+ # include Open4
14
+ # pid, stdin, stdout, stderr = popen4('nroff -man')
15
+
16
+ require 'fcntl'
17
+
18
+ module Open4
19
+ #--{{{
20
+
21
+ if false
22
+ PROCESSES = Hash.new
23
+
24
+ orig_sigchld_handler = trap("CLD") do |*args|
25
+ begin
26
+ PROCESSES.each do |pid, foo|
27
+ if (Process.waitpid2(pid, Process::WNOHANG) == pid)
28
+ PROCESSES.delete(pid)
29
+ end
30
+ end
31
+ rescue Errno::ECHILD
32
+ nil
33
+ end
34
+ orig_sigchld_handler.call(*args) if (not (orig_sigchld_handler.nil?))
35
+ end
36
+ end
37
+
38
+ #
39
+ # [ pid, stdin, stdout, stderr ] = popen4 command
40
+ #
41
+
42
+ def popen4(*cmd)
43
+ #--{{{
44
+
45
+ pw = IO::pipe # pipe[1] for read, pipe[0] for write
46
+ pr = IO::pipe # pipe[0] for read, pipe[1] for write
47
+ pe = IO::pipe # pipe[0] for read, pipe[1] for write
48
+ ps = IO::pipe # pipe[0] for read, pipe[1] for write
49
+
50
+ verbose = $VERBOSE
51
+ begin
52
+ $VERBOSE = nil # shut up warning about forking in threads, world writable
53
+ # dirs, etc
54
+
55
+ ps[1].fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
56
+
57
+ cid = fork {
58
+ # child
59
+ pw[1].close
60
+ STDIN.reopen(pw[0])
61
+ pw[0].close
62
+
63
+ pr[0].close
64
+ STDOUT.reopen(pr[1])
65
+ pr[1].close
66
+
67
+ pe[0].close
68
+ STDERR.reopen(pe[1])
69
+ pe[1].close
70
+
71
+ STDOUT.sync = true
72
+ STDERR.sync = true
73
+
74
+ begin
75
+ exec(*cmd)
76
+ raise "exec returned!"
77
+ rescue Exception
78
+ Marshal.dump($!, ps[1])
79
+ ps[1].flush
80
+ end
81
+ ps[1].close unless (ps[1].closed?)
82
+ exit!
83
+ }
84
+ ensure
85
+ $VERBOSE = verbose
86
+ end
87
+
88
+ pw[0].close
89
+ pr[1].close
90
+ pe[1].close
91
+ ps[1].close
92
+
93
+ exc = nil
94
+ begin
95
+ exc = Marshal.load(ps[0])
96
+ rescue EOFError # If we get an EOF error, then the exec was successful
97
+ end
98
+
99
+ if (not (exc.nil?)) then
100
+ raise exc
101
+ end
102
+
103
+ # PROCESSES[cid] = true
104
+
105
+ pi = [pw[1], pr[0], pe[0]]
106
+ pw[1].sync = true
107
+ if defined? yield
108
+ begin
109
+ yield(cid, *pi)
110
+ return((Process.waitpid2(cid, 1)).last)
111
+ ensure
112
+ pi.each{|p| p.close unless p.closed?}
113
+ end
114
+ end
115
+ [cid, pw[1], pr[0], pe[0]]
116
+ #--}}}
117
+ end
118
+
119
+ alias open4 popen4
120
+ module_function :popen4
121
+ module_function :open4
122
+
123
+ #--}}}
124
+ end
125
+
126
+ if $0 == __FILE__
127
+ status = Open4::popen4('sh'){|cid,i,o,e|i.puts 'echo 42';i.close; puts o.read;}
128
+ p [status]
129
+ p status.exitstatus
130
+ p status == 0
131
+ end
data/open4-0.2.0.gem ADDED
File without changes
data/sample/block.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'open4'
2
+ #
3
+ # when using block form the child process is automatically waited using
4
+ # waitpid2
5
+ #
6
+
7
+ status =
8
+ Open4::popen4("sh") do |pid, stdin, stdout, stderr|
9
+ stdin.puts "echo 42.out"
10
+ stdin.puts "echo 42.err 1>&2"
11
+ stdin.close
12
+
13
+ puts "pid : #{ pid }"
14
+ puts "stdout : #{ stdout.read.strip }"
15
+ puts "stderr : #{ stderr.read.strip }"
16
+ end
17
+
18
+ puts "status : #{ status.inspect }"
19
+ puts "exitstatus : #{ status.exitstatus }"
@@ -0,0 +1,3 @@
1
+ require "open4"
2
+
3
+ Open4::popen4 "noexist"
data/sample/simple.rb ADDED
@@ -0,0 +1,15 @@
1
+ require "open4"
2
+
3
+ pid, stdin, stdout, stderr = Open4::popen4 "sh"
4
+
5
+ stdin.puts "echo 42.out"
6
+ stdin.puts "echo 42.err 1>&2"
7
+ stdin.close
8
+
9
+ ignored, status = Process::waitpid2 pid
10
+
11
+ puts "pid : #{ pid }"
12
+ puts "stdout : #{ stdout.read.strip }"
13
+ puts "stderr : #{ stderr.read.strip }"
14
+ puts "status : #{ status.inspect }"
15
+ puts "exitstatus : #{ status.exitstatus }"
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: open4
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.2.0
7
+ date: 2006-02-13 00:00:00.000000 -07:00
8
+ summary: open4
9
+ require_paths:
10
+ - lib
11
+ email: ara.t.howard@noaa.gov
12
+ homepage: http://codeforpeople.com/lib/ruby/open4/
13
+ rubyforge_project:
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ signing_key:
28
+ cert_chain:
29
+ authors:
30
+ - Ara T. Howard
31
+ files:
32
+ - lib
33
+ - install
34
+ - install.rb
35
+ - README
36
+ - sample
37
+ - gemspec.rb
38
+ - open4-0.2.0.gem
39
+ - lib/open4.rb
40
+ - lib/open4-0.2.0.rb
41
+ - sample/block.rb
42
+ - sample/simple.rb
43
+ - sample/exception.rb
44
+ test_files: []
45
+ rdoc_options: []
46
+ extra_rdoc_files: []
47
+ executables: []
48
+ extensions: []
49
+ requirements: []
50
+ dependencies: []