subexec 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/{README.rdoc → README.md} +13 -10
  2. data/lib/subexec.rb +44 -29
  3. metadata +46 -35
  4. data/VERSION +0 -1
@@ -1,8 +1,8 @@
1
- = Subexec
1
+ # Subexec
2
2
  by Peter Kieltyka
3
3
  http://github/nulayer/subexec
4
4
 
5
- === Description
5
+ ## Description
6
6
 
7
7
  Subexec is a simple library that spawns an external command with
8
8
  an optional timeout parameter. It relies on Ruby 1.9's Process.spawn
@@ -12,18 +12,21 @@ Useful for libraries that are Ruby wrappers for CLI's. For example,
12
12
  resizing images with ImageMagick's mogrify command sometimes stalls
13
13
  and never returns control back to the original process. Enter Subexec.
14
14
 
15
- === Usage
15
+ Tested with MRI 1.9.3, 1.9.2, 1.8.7
16
16
 
17
- sub = Subexec.run "echo 'hello' && sleep 3", :timeout => 5
18
- puts sub.output # returns: hello
19
- puts sub.exitstatus # returns: 0
17
+ ## Usage
20
18
 
21
- sub = Subexec.run "echo 'hello' && sleep 3", :timeout => 1
22
- puts sub.output # returns:
23
- puts sub.exitstatus # returns:
19
+ ```ruby
20
+ sub = Subexec.run "echo 'hello' && sleep 3", :timeout => 5
21
+ puts sub.output # returns: hello
22
+ puts sub.exitstatus # returns: 0
24
23
 
24
+ sub = Subexec.run "echo 'hello' && sleep 3", :timeout => 1
25
+ puts sub.output # returns:
26
+ puts sub.exitstatus # returns:`
27
+ ```
25
28
 
26
- === Limitations
29
+ ## Limitations
27
30
 
28
31
  Only Ruby 1.9 can spawn non-blocking subprocesses, via Process.spawn.
29
32
  So Ruby 1.8 support is sheerly for backwards compatibility.
data/lib/subexec.rb CHANGED
@@ -1,8 +1,8 @@
1
- # = Subexec
1
+ # # Subexec
2
2
  # * by Peter Kieltyka
3
- # * http://github/nulayer/subprocess
3
+ # * http://github/nulayer/subexec
4
4
  #
5
- # === Description
5
+ # ## Description
6
6
  #
7
7
  # Subexec is a simple library that spawns an external command with
8
8
  # an optional timeout parameter. It relies on Ruby 1.9's Process.spawn
@@ -11,9 +11,9 @@
11
11
  # Useful for libraries that are Ruby wrappers for CLI's. For example,
12
12
  # resizing images with ImageMagick's mogrify command sometimes stalls
13
13
  # and never returns control back to the original process. Subexec
14
- # executes mogrify and preempts if gets lost.
14
+ # executes mogrify and preempts if it gets lost.
15
15
  #
16
- # === Usage
16
+ # ## Usage
17
17
  #
18
18
  # # Print hello
19
19
  # sub = Subexec.run "echo 'hello' && sleep 3", :timeout => 5
@@ -26,14 +26,15 @@
26
26
  # puts sub.exitstatus # returns:
27
27
 
28
28
  class Subexec
29
+ VERSION = '0.2.0'
29
30
 
30
- attr_accessor :pid
31
- attr_accessor :command
32
- attr_accessor :timeout
33
- attr_accessor :timer
34
- attr_accessor :output
35
- attr_accessor :exitstatus
36
- attr_accessor :lang
31
+ attr_accessor :pid,
32
+ :command,
33
+ :lang,
34
+ :output,
35
+ :exitstatus,
36
+ :timeout,
37
+ :log_file
37
38
 
38
39
  def self.run(command, options={})
39
40
  sub = new(command, options)
@@ -42,13 +43,15 @@ class Subexec
42
43
  end
43
44
 
44
45
  def initialize(command, options={})
45
- self.command = command
46
- self.timeout = options[:timeout] || -1 # default is to never timeout
47
- self.lang = options[:lang] || "C"
46
+ self.command = command
47
+ self.lang = options[:lang] || "C"
48
+ self.timeout = options[:timeout] || -1 # default is to never timeout
49
+ self.log_file = options[:log_file]
50
+ self.exitstatus = 0
48
51
  end
49
52
 
50
53
  def run!
51
- if timeout > 0 && RUBY_VERSION >= '1.9'
54
+ if RUBY_VERSION >= '1.9'
52
55
  spawn
53
56
  else
54
57
  exec
@@ -59,27 +62,41 @@ class Subexec
59
62
  private
60
63
 
61
64
  def spawn
62
- r, w = IO.pipe
63
- self.pid = Process.spawn({'LANG' => self.lang}, command, STDERR=>w, STDOUT=>w)
65
+ # TODO: weak implementation for log_file support.
66
+ # Ideally, the data would be piped through to both descriptors
67
+ r, w = IO.pipe
68
+ if !log_file.nil?
69
+ self.pid = Process.spawn({'LANG' => self.lang}, command, [:out, :err] => [log_file, 'a'])
70
+ else
71
+ self.pid = Process.spawn({'LANG' => self.lang}, command, STDERR=>w, STDOUT=>w)
72
+ end
64
73
  w.close
65
-
66
- self.timer = Time.now + timeout
74
+
75
+ @timer = Time.now + timeout
67
76
  timed_out = false
68
77
 
69
- loop do
78
+ waitpid = Proc.new do
70
79
  begin
71
80
  flags = (timeout > 0 ? Process::WUNTRACED|Process::WNOHANG : 0)
72
- ret = Process.waitpid(pid, flags)
81
+ Process.waitpid(pid, flags)
73
82
  rescue Errno::ECHILD
74
83
  break
75
84
  end
85
+ end
76
86
 
77
- break if ret == pid
78
- sleep 0.01
79
- if Time.now > timer
80
- timed_out = true
81
- break
87
+ if timeout > 0
88
+ loop do
89
+ ret = waitpid.call
90
+
91
+ break if ret == pid
92
+ sleep 0.01
93
+ if Time.now > @timer
94
+ timed_out = true
95
+ break
96
+ end
82
97
  end
98
+ else
99
+ waitpid.call
83
100
  end
84
101
 
85
102
  if timed_out
@@ -98,8 +115,6 @@ class Subexec
98
115
 
99
116
  def exec
100
117
  self.output = `export LANG=#{lang} && #{command} 2>&1`
101
- self.exitstatus = $?.exitstatus
102
118
  end
103
119
 
104
120
  end
105
-
metadata CHANGED
@@ -1,59 +1,70 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: subexec
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
4
5
  prerelease:
5
- version: 0.1.0
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Peter Kieltyka
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-03-03 00:00:00 -05:00
14
- default_executable:
15
- dependencies: []
16
-
17
- description: Subexec spawns an external command with a timeout
18
- email:
12
+ date: 2011-11-01 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70265363645600 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70265363645600
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70265363643540 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 2.7.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70265363643540
36
+ description: Subexec spawns a subprocess with an optional timeout
37
+ email:
19
38
  - peter@nulayer.com
20
39
  executables: []
21
-
22
40
  extensions: []
23
-
24
41
  extra_rdoc_files: []
25
-
26
- files:
27
- - README.rdoc
28
- - VERSION
42
+ files:
43
+ - README.md
29
44
  - lib/subexec.rb
30
- has_rdoc: true
31
45
  homepage: http://github.com/nulayer/subexec
32
46
  licenses: []
33
-
34
47
  post_install_message:
35
48
  rdoc_options: []
36
-
37
- require_paths:
49
+ require_paths:
38
50
  - lib
39
- required_ruby_version: !ruby/object:Gem::Requirement
51
+ required_ruby_version: !ruby/object:Gem::Requirement
40
52
  none: false
41
- requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- version: "0"
45
- required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
58
  none: false
47
- requirements:
48
- - - ">="
49
- - !ruby/object:Gem::Version
50
- version: "0"
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
51
63
  requirements: []
52
-
53
64
  rubyforge_project:
54
- rubygems_version: 1.5.3
65
+ rubygems_version: 1.8.11
55
66
  signing_key:
56
67
  specification_version: 3
57
- summary: Subexec spawns an external command with a timeout
68
+ summary: Subexec spawns a subprocess with an optional timeout
58
69
  test_files: []
59
-
70
+ has_rdoc:
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.1.0