open4 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []