popen4 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/CHANGES +7 -0
  2. data/LICENSE +71 -0
  3. data/README.rdoc +50 -0
  4. data/Rakefile +131 -0
  5. data/lib/popen4.rb +100 -0
  6. data/tests/popen4_test.rb +79 -0
  7. metadata +80 -0
data/CHANGES ADDED
@@ -0,0 +1,7 @@
1
+ == 0.1.1 - 12-Jun-2006
2
+ * Fixed Bug 4742
3
+ - open3.so Open4 fails to return Process::Status on Windows 2000.
4
+ - Thanks to Park Heesob!
5
+
6
+ == 0.1.0 - 10-Jun-2006
7
+ * Initial release
data/LICENSE ADDED
@@ -0,0 +1,71 @@
1
+ == POpen4 License
2
+
3
+ POpen4 is copyright John-Mason P. Shackelford (john-mason@shackelford.org)
4
+ and made available under the terms of Ruby's license, included below for your
5
+ convenience.
6
+
7
+ == win32-open3 License
8
+
9
+ The the win32-open3 library may be included in this distribution of POpen4. If
10
+ so, POpen4 users must also comply with the terms of its license. Park Heesob and
11
+ Daniel Berger hold the copyright on most of the win32-open3 code which also
12
+ happens to be licensed under the same terms as Ruby.
13
+
14
+ == Ruby's License
15
+
16
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
17
+ You can redistribute it and/or modify it under either the terms of the GPL
18
+ (see the file GPL), or the conditions below:
19
+
20
+ 1. You may make and give away verbatim copies of the source form of the
21
+ software without restriction, provided that you duplicate all of the
22
+ original copyright notices and associated disclaimers.
23
+
24
+ 2. You may modify your copy of the software in any way, provided that
25
+ you do at least ONE of the following:
26
+
27
+ a) place your modifications in the Public Domain or otherwise
28
+ make them Freely Available, such as by posting said
29
+ modifications to Usenet or an equivalent medium, or by allowing
30
+ the author to include your modifications in the software.
31
+
32
+ b) use the modified software only within your corporation or
33
+ organization.
34
+
35
+ c) give non-standard binaries non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 3. You may distribute the software in object code or binary form,
41
+ provided that you do at least ONE of the following:
42
+
43
+ a) distribute the binaries and library files of the software,
44
+ together with instructions (in the manual page or equivalent)
45
+ on where to get the original distribution.
46
+
47
+ b) accompany the distribution with the machine-readable source of
48
+ the software.
49
+
50
+ c) give non-standard binaries non-standard names, with
51
+ instructions on where to get the original software distribution.
52
+
53
+ d) make other distribution arrangements with the author.
54
+
55
+ 4. You may modify and include the part of the software into any other
56
+ software (possibly commercial). But some files in the distribution
57
+ are not written by the author, so that they are not under these terms.
58
+
59
+ For the list of those files and their copying conditions, see the
60
+ file LEGAL.
61
+
62
+ 5. The scripts and library files supplied as input to or produced as
63
+ output from the software do not automatically fall under the
64
+ copyright of the software, but belong to whomever generated them,
65
+ and may be sold commercially, and may be aggregated with this
66
+ software.
67
+
68
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
69
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
70
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
71
+ PURPOSE.
@@ -0,0 +1,50 @@
1
+ == Description
2
+ POpen4 provides the Rubyist a single API across platforms for executing a
3
+ command in a child process with handles on stdout, stderr, stdin streams as well
4
+ as access to the process ID and exit status. It does very little other than to
5
+ provide an easy way to use either Ara Howard's Open4 library or the win32-popen3
6
+ library by Park Heesob and Daniel Berger depending on your platform and without
7
+ having to code around the slight differences in their APIs.
8
+
9
+ Consider this my first attempt at a response to
10
+ {Daniel's request}[http://groups.google.com/group/comp.lang.ruby/msg/44ba016610fa8878]
11
+ for a consensus on the API back in 2005.
12
+
13
+ It is my hope that this project will be shortly absorbed or replaced with a
14
+ better solution. POpen4 offers very little in the way of features or
15
+ flexibility, but it does work across platforms without extra coding.
16
+ == Notes
17
+ Rather than adopting either Open4's API or win32-open3's (they differ in several
18
+ respects, but most obviously in the order in which streams are passed to the
19
+ block) I am proposing a third API for couple of reasons. First, Open4 passes the
20
+ PID first and win32-open3 passes stdin neither of which seem to me to be the
21
+ streams we are most likely to use when we don't need all four. POpen4 passes
22
+ stdout and stderr first so that when the others are not required we can omit
23
+ them from the block. Second, I thought it best to break everybody's code rather
24
+ than to be a drop in replacement on one platform and be a surprise on another.
25
+ No surprises--it's a new API on either platform.
26
+
27
+ == Installation
28
+
29
+ $ gem install --remote --include-dependencies POpen4
30
+
31
+ Presently POpen4 ships in four platform specific gems:
32
+
33
+ POpen4-0.1.0-unix.gem
34
+ POpen4-0.1.0-win32-1.8.2-VC7.gem
35
+ POpen4-0.1.0-win32-1.8.4-VC6.gem
36
+ POpen4-0.1.0-win32-source.gem
37
+
38
+ Users of Linux, Unix, BSD, etc., will want the unix package. Ara's Open4 gem
39
+ is a dependency. Users of the Ruby One-Click Installer (OCI) will want to select
40
+ the gem appropriate their version of Ruby. The real issue here is compiler
41
+ version. The wrong version will SEGFAULT due to some incompatibility somewhere
42
+ in the VC++ compiler or libraries (which I really wish we could resolve,
43
+ but oh well). Others using a Windows platform but not the OCI will want to
44
+ compile from source using last of these gems. Be sure to have your environment
45
+ set up for doing a build before running <tt>gem install POpen4</tt>.
46
+
47
+ == Acknowledgements
48
+ Ara Howard, Park Heesob, Daniel Berger and others have done the real work. Many
49
+ thanks to them for the many hours they have poured into sharing their work with
50
+ the Ruby community at large.
@@ -0,0 +1,131 @@
1
+ require 'rubygems'
2
+ require 'rubygems/user_interaction'
3
+ require 'rake/gempackagetask'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+
7
+ PROJECT_VERSION = "0.1.1"
8
+
9
+ task :default => [:test]
10
+
11
+ # Test --------------------------------------------------------------------
12
+
13
+ desc "Run the unit tests"
14
+ task :test do
15
+ Rake::TestTask.new("test") do |t|
16
+ t.libs << "tests"
17
+ t.pattern = 'tests/*_test.rb'
18
+ t.verbose = true
19
+ end
20
+ end
21
+
22
+ # Documentation -----------------------------------------------------------
23
+ desc "Generate RDoc"
24
+ rd = Rake::RDocTask.new("rdoc") { |rdoc|
25
+ rdoc.rdoc_dir = 'rdoc'
26
+ rdoc.title = "POpen4 -- Open4 cross-platform"
27
+ rdoc.options << '--main' << 'README'
28
+ rdoc.rdoc_files.include('README', 'LICENSE', 'CHANGES')
29
+ rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc').exclude('lib/open3.rb')
30
+ }
31
+
32
+ # GEM Packaging -----------------------------------------------------------
33
+
34
+ POPEN4_GENERIC = FileList["{tests,lib}/popen4*.rb"].add('*').to_a
35
+
36
+ # -- WIN32 1.8.2 ----------------
37
+
38
+ spec = Gem::Specification.new do |s|
39
+ s.name = "POpen4"
40
+ s.version = PROJECT_VERSION
41
+ s.author = "John-Mason P. Shackelford"
42
+ s.email = "john-mason@shackelford.org"
43
+ s.platform = 'win32-1.8.2-VC7'
44
+ s.summary = "Open4 cross-platform"
45
+ s.files = POPEN4_GENERIC + FileList['lib/1.8.2*/*', 'lib/open3.rb'].to_a
46
+ s.require_path = "lib"
47
+ s.autorequire = "popen4.rb"
48
+ s.has_rdoc = true
49
+ s.add_dependency("Platform", ">= 0.4.0")
50
+ end
51
+
52
+ task :package => [:test]
53
+ Rake::GemPackageTask.new( spec ) do |pkg|
54
+ pkg.gem_spec = spec
55
+ pkg.need_zip = false
56
+ pkg.need_tar = false
57
+ end
58
+
59
+ # -- WIN32 1.8.4 ----------------
60
+
61
+ spec = Gem::Specification.new do |s|
62
+ s.name = "POpen4"
63
+ s.version = PROJECT_VERSION
64
+ s.author = "John-Mason P. Shackelford"
65
+ s.email = "john-mason@shackelford.org"
66
+ s.platform = 'win32-1.8.4-VC6'
67
+ s.summary = "Open4 cross-platform"
68
+ s.files = POPEN4_GENERIC + FileList['lib/1.8.4*/*', 'lib/open3.rb'].to_a
69
+ s.require_path = "lib"
70
+ s.autorequire = "popen4.rb"
71
+ s.has_rdoc = true
72
+ s.add_dependency("Platform", ">= 0.4.0")
73
+ end
74
+
75
+ task :package => [:test]
76
+ Rake::GemPackageTask.new( spec ) do |pkg|
77
+ pkg.gem_spec = spec
78
+ pkg.need_zip = false
79
+ pkg.need_tar = false
80
+ end
81
+
82
+ # -- WIN32 src-only ----------------
83
+
84
+ spec = Gem::Specification.new do |s|
85
+ s.name = "POpen4"
86
+ s.version = PROJECT_VERSION
87
+ s.author = "John-Mason P. Shackelford"
88
+ s.email = "john-mason@shackelford.org"
89
+ s.platform = 'win32-source'
90
+ s.summary = "Open4 cross-platform"
91
+ s.files = POPEN4_GENERIC + FileList['{ext}/**/*','lib/open3.rb'].to_a
92
+ s.require_path = "lib"
93
+ s.autorequire = "popen4.rb"
94
+ s.has_rdoc = true
95
+ s.add_dependency("Platform", ">= 0.4.0")
96
+ s.extensions << 'ext/win32-open3/extconf.rb'
97
+ end
98
+
99
+ task :package => [:test]
100
+ Rake::GemPackageTask.new( spec ) do |pkg|
101
+ pkg.gem_spec = spec
102
+ pkg.need_zip = false
103
+ pkg.need_tar = false
104
+ end
105
+
106
+ # -- Unix / OS X / BSD / Linux ----------------
107
+
108
+ spec = Gem::Specification.new do |s|
109
+ s.name = "POpen4"
110
+ s.version = PROJECT_VERSION
111
+ s.author = "John-Mason P. Shackelford"
112
+ s.email = "john-mason@shackelford.org"
113
+ s.platform = 'unix'
114
+ s.summary = "Open4 cross-platform"
115
+ s.files = POPEN4_GENERIC
116
+ s.require_path = "lib"
117
+ s.autorequire = "popen4.rb"
118
+ s.has_rdoc = true
119
+ s.add_dependency("Platform", ">= 0.4.0")
120
+ s.add_dependency("open4", ">= 0.4.0")
121
+ end
122
+
123
+ task :package => [:test]
124
+ Rake::GemPackageTask.new( spec ) do |pkg|
125
+ pkg.gem_spec = spec
126
+ pkg.need_zip = false
127
+ pkg.need_tar = false
128
+ end
129
+
130
+
131
+
@@ -0,0 +1,100 @@
1
+ require 'rubygems'
2
+ require 'platform'
3
+ #require_gem 'Platform', '>= 0.4.0'
4
+
5
+ case Platform::OS
6
+
7
+ # win32/popen4 yields stdin, stdout, stderr and pid, respectively
8
+ when :win32
9
+
10
+ require File.join( File.dirname( __FILE__ ), 'open3')
11
+
12
+ # POpen4 provides the Rubyist a single API across platforms for executing a
13
+ # command in a child process with handles on stdout, stderr, and stdin streams
14
+ # as well as access to the process ID and exit status.
15
+ #
16
+ # Consider the following example (borrowed from Open4):
17
+ #
18
+ # require 'rubygems'
19
+ # require 'popen4'
20
+ #
21
+ # status =
22
+ # POpen4::popen4("cmd") do |stdout, stderr, stdin, pid|
23
+ # stdin.puts "echo hello world!"
24
+ # stdin.puts "echo ERROR! 1>&2"
25
+ # stdin.puts "exit"
26
+ # stdin.close
27
+ #
28
+ # puts "pid : #{ pid }"
29
+ # puts "stdout : #{ stdout.read.strip }"
30
+ # puts "stderr : #{ stderr.read.strip }"
31
+ # end
32
+ #
33
+ # puts "status : #{ status.inspect }"
34
+ # puts "exitstatus : #{ status.exitstatus }"
35
+ #
36
+ module POpen4
37
+ # Starts a new process and hands IO objects representing the subprocess
38
+ # stdout, stderr, stdin streams and the pid (respectively) to the block
39
+ # supplied. If the command could not be started, return nil.
40
+ #
41
+ # The mode argument may be set to t[ext] or b[inary] and is used only on
42
+ # Windows platforms.
43
+ #
44
+ # The stdin stream and/or pid may be omitted from the block parameter list
45
+ # if they are not required.
46
+ def self.popen4(command, mode = "t") # :yields: stdout, stderr, stdin, pid
47
+
48
+ err_output = nil
49
+ status = Open4.popen4(command, mode) do |stdin,stdout,stderr,pid|
50
+ yield stdout, stderr, stdin, pid
51
+
52
+ # On windows we will always get an exit status of 3 unless
53
+ # we read to the end of the streams so we do this on all platforms
54
+ # so that our behavior is always the same.
55
+ stdout.read unless stdout.eof?
56
+
57
+ # On windows executing a non existent command does not raise an error
58
+ # (as in unix) so on unix we return nil instead of a status object and
59
+ # on windows we try to determine if we couldn't start the command and
60
+ # return nil instead of the Process::Status object.
61
+ stderr.rewind
62
+ err_output = stderr.read
63
+ end
64
+
65
+ if status.exitstatus == 1 &&
66
+ err_output.match(/is not recognized as an internal or external command/)
67
+ return nil
68
+ end
69
+
70
+ return status
71
+ end # def
72
+ end # module
73
+
74
+
75
+ else # unix popen4 yields pid, stdin, stdout and stderr, respectively
76
+ # :enddoc:
77
+ require 'open4'
78
+ module POpen4
79
+ def self.popen4(command, mode = "t")
80
+ begin
81
+ return status = Open4.popen4(command) do |pid,stdin,stdout,stderr|
82
+ yield stdout, stderr, stdin, pid
83
+ # On windows we will always get an exit status of 3 unless
84
+ # we read to the end of the streams so we do this on all platforms
85
+ # so that our behavior is always the same.
86
+ stdout.read unless stdout.eof?
87
+ stderr.read unless stderr.eof?
88
+ end
89
+ rescue Errno::ENOENT => e
90
+ # On windows executing a non existent command does not raise an error
91
+ # (as in unix) so on unix we return nil instead of a status object and
92
+ # on windows we try to determine if we couldn't start the command and
93
+ # return nil instead of the Process::Status object.
94
+ return nil
95
+ end
96
+ end #def
97
+ end #module
98
+
99
+ end
100
+
@@ -0,0 +1,79 @@
1
+ $: << File.join( File.dirname( __FILE__ ), '../lib/')
2
+
3
+ require 'test/unit'
4
+ require 'popen4'
5
+
6
+ require 'rubygems'
7
+ require_gem 'Platform', '>= 0.4.0'
8
+
9
+ class POpen4Test < Test::Unit::TestCase
10
+
11
+ case Platform::OS
12
+ when :win32
13
+ CMD_SHELL = "cmd"
14
+ CMD_STDERR = "ruby -e \"$stderr.puts 'ruby'\""
15
+ CMD_EXIT = "ruby -e \"$stdout.puts 'ruby'; exit 1\""
16
+ else # unix
17
+ CMD_SHELL = "sh"
18
+ CMD_STDERR = "ruby -e '$stderr.puts \"ruby\"'"
19
+ CMD_EXIT = "ruby -e '$stdout.puts \"ruby\"; exit 1'"
20
+ end
21
+ CMD_GOOD = "ruby --version"
22
+ CMD_BAD = CMD_GOOD.reverse
23
+
24
+ def test_popen4_block_good_cmd
25
+ assert_nothing_raised do
26
+ POpen4.popen4(CMD_GOOD){ |pout, perr, pin, pid| }
27
+ end
28
+ end
29
+
30
+ def test_popen4_block_bad_cmd
31
+ status = nil
32
+ assert_nothing_raised do
33
+ status = POpen4.popen4(CMD_BAD){ |pout, perr, pin, pid| }
34
+ end
35
+ assert_nil status
36
+ end
37
+
38
+ def test_popen4_block_status
39
+ status = POpen4.popen4(CMD_GOOD) do |pout, perr, pin, pid|
40
+ assert_kind_of(IO, pin)
41
+ assert_kind_of(IO, pout)
42
+ assert_kind_of(IO, perr)
43
+ assert_kind_of(Fixnum, pid)
44
+ end
45
+ assert_kind_of Process::Status, status
46
+ end
47
+
48
+ def test_open4_block_read_stdout
49
+ status = POpen4.popen4(CMD_GOOD) do |pout, perr|
50
+ assert_match(/ruby \d\.\d\.\d/, pout.gets)
51
+ end
52
+ assert_equal 0, status.exitstatus
53
+ end
54
+
55
+ def test_open4_block_read_stderr
56
+ status = POpen4.popen4(CMD_STDERR) do |pout, perr|
57
+ assert_match "ruby", perr.gets
58
+ end
59
+ assert_equal 0, status.exitstatus
60
+ end
61
+
62
+ def test_open4_block_exitstatus
63
+ status = POpen4.popen4(CMD_EXIT) do |pout, perr|
64
+ assert_match "ruby", pout.gets
65
+ end
66
+ assert_kind_of Process::Status, status
67
+ assert_equal 1, status.exitstatus
68
+ end
69
+
70
+ def test_open4_block_write_stdin
71
+ status = POpen4.popen4(CMD_SHELL) do |pout, perr, pin|
72
+ pin.puts CMD_GOOD
73
+ pin.puts "exit"
74
+ pin.close
75
+ assert_match(/ruby \d\.\d\.\d/, pout.readlines.join)
76
+ end
77
+ assert_equal 0, status.exitstatus
78
+ end
79
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: popen4
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - John-Mason P. Shackelford
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-03 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: Platform
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.4.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: open4
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.4.0
34
+ version:
35
+ description: POpen4 provides the Rubyist a single API across platforms for executing a command in a child process with handles on stdout, stderr, stdin streams as well as access to the process ID and exit status.
36
+ email: john-mason@shackelford.org
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - CHANGES
43
+ - LICENSE
44
+ - README.rdoc
45
+ files:
46
+ - Rakefile
47
+ - lib/popen4.rb
48
+ - CHANGES
49
+ - LICENSE
50
+ - README.rdoc
51
+ has_rdoc: true
52
+ homepage: http://github.com/shairontoledo/popen4
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options: []
57
+
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.3.4
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Open4 cross-platform
79
+ test_files:
80
+ - tests/popen4_test.rb