subexec 0.2.2 → 0.2.3

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.
Files changed (2) hide show
  1. data/lib/subexec.rb +38 -38
  2. metadata +42 -32
@@ -1,32 +1,32 @@
1
1
  # # Subexec
2
2
  # * by Peter Kieltyka
3
3
  # * http://github/nulayer/subexec
4
- #
4
+ #
5
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
9
9
  # method. Also, it works with synchronous and asynchronous code.
10
- #
10
+ #
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
14
  # executes mogrify and preempts if it gets lost.
15
- #
15
+ #
16
16
  # ## Usage
17
- #
17
+ #
18
18
  # # Print hello
19
19
  # sub = Subexec.run "echo 'hello' && sleep 3", :timeout => 5
20
20
  # puts sub.output # returns: hello
21
21
  # puts sub.exitstatus # returns: 0
22
- #
22
+ #
23
23
  # # Timeout process after a second
24
24
  # sub = Subexec.run "echo 'hello' && sleep 3", :timeout => 1
25
- # puts sub.output # returns:
25
+ # puts sub.output # returns:
26
26
  # puts sub.exitstatus # returns:
27
27
 
28
28
  class Subexec
29
- VERSION = '0.2.2'
29
+ VERSION = '0.2.3'
30
30
 
31
31
  attr_accessor :pid,
32
32
  :command,
@@ -41,7 +41,7 @@ class Subexec
41
41
  sub.run!
42
42
  sub
43
43
  end
44
-
44
+
45
45
  def initialize(command, options={})
46
46
  self.command = command
47
47
  self.lang = options[:lang] || "C"
@@ -49,7 +49,7 @@ class Subexec
49
49
  self.log_file = options[:log_file]
50
50
  self.exitstatus = 0
51
51
  end
52
-
52
+
53
53
  def run!
54
54
  if RUBY_VERSION >= '1.9' && RUBY_ENGINE != 'jruby'
55
55
  spawn
@@ -60,43 +60,43 @@ class Subexec
60
60
 
61
61
 
62
62
  private
63
-
63
+
64
64
  def spawn
65
65
  # TODO: weak implementation for log_file support.
66
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
67
+ r, w = IO.pipe
68
+
69
+ log_to_file = !log_file.nil?
70
+ log_opts = log_to_file ? {[:out, :err] => [log_file, 'a']} : {STDERR=>w, STDOUT=>w}
71
+ self.pid = Process.spawn({'LANG' => self.lang}, command, log_opts)
73
72
  w.close
74
-
73
+
75
74
  @timer = Time.now + timeout
76
75
  timed_out = false
77
76
 
78
- waitpid = Proc.new do
79
- begin
80
- flags = (timeout > 0 ? Process::WUNTRACED|Process::WNOHANG : 0)
81
- Process.waitpid(pid, flags)
77
+ self.output = ''
78
+
79
+ append_to_output = Proc.new do
80
+ self.output << r.readlines.join('') unless log_to_file
81
+ end
82
+
83
+ loop do
84
+ ret = begin
85
+ Process.waitpid(pid, Process::WUNTRACED|Process::WNOHANG)
82
86
  rescue Errno::ECHILD
83
87
  break
84
88
  end
85
- end
86
89
 
87
- if timeout > 0
88
- loop do
89
- ret = waitpid.call
90
+ break if ret == pid
90
91
 
91
- break if ret == pid
92
- sleep 0.01
93
- if Time.now > @timer
94
- timed_out = true
95
- break
96
- end
92
+ append_to_output.call
93
+
94
+ if timeout > 0 && Time.now > @timer
95
+ timed_out = true
96
+ break
97
97
  end
98
- else
99
- waitpid.call
98
+
99
+ sleep 0.01
100
100
  end
101
101
 
102
102
  if timed_out
@@ -106,18 +106,18 @@ class Subexec
106
106
  else
107
107
  # The subprocess exited on its own
108
108
  self.exitstatus = $?.exitstatus
109
- self.output = r.readlines.join("")
109
+ append_to_output.call
110
110
  end
111
111
  r.close
112
-
112
+
113
113
  self
114
114
  end
115
-
115
+
116
116
  def exec
117
117
  if !(RUBY_PLATFORM =~ /win32|mswin|mingw/).nil?
118
118
  self.output = `set LANG=#{lang} && #{command} 2>&1`
119
119
  else
120
- self.output = `LANG=#{lang} && export $LANG && #{command} 2>&1`
120
+ self.output = `LANG=#{lang} && export LANG && #{command} 2>&1`
121
121
  end
122
122
  self.exitstatus = $?.exitstatus
123
123
  end
metadata CHANGED
@@ -1,48 +1,50 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: subexec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
5
- prerelease:
4
+ version: 0.2.3
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Peter Kieltyka
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-20 00:00:00.000000000 Z
12
+ date: 2013-04-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
16
+ version_requirements: !ruby/object:Gem::Requirement
18
17
  requirements:
19
- - - ! '>='
18
+ - - ">="
20
19
  - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :development
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
20
+ version: !binary |-
21
+ MA==
25
22
  none: false
23
+ requirement: !ruby/object:Gem::Requirement
26
24
  requirements:
27
- - - ! '>='
25
+ - - ">="
28
26
  - !ruby/object:Gem::Version
29
- version: '0'
27
+ version: !binary |-
28
+ MA==
29
+ none: false
30
+ prerelease: false
31
+ type: :development
30
32
  - !ruby/object:Gem::Dependency
31
33
  name: rspec
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
+ version_requirements: !ruby/object:Gem::Requirement
34
35
  requirements:
35
- - - ~>
36
+ - - "~>"
36
37
  - !ruby/object:Gem::Version
37
38
  version: 2.7.0
38
- type: :development
39
- prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
39
  none: false
40
+ requirement: !ruby/object:Gem::Requirement
42
41
  requirements:
43
- - - ~>
42
+ - - "~>"
44
43
  - !ruby/object:Gem::Version
45
44
  version: 2.7.0
45
+ none: false
46
+ prerelease: false
47
+ type: :development
46
48
  description: Subexec spawns a subprocess with an optional timeout
47
49
  email:
48
50
  - peter@nulayer.com
@@ -53,28 +55,36 @@ files:
53
55
  - README.md
54
56
  - lib/subexec.rb
55
57
  homepage: http://github.com/nulayer/subexec
56
- licenses: []
57
- post_install_message:
58
+ licenses:
59
+ - MIT
60
+ post_install_message:
58
61
  rdoc_options: []
59
62
  require_paths:
60
63
  - lib
61
64
  required_ruby_version: !ruby/object:Gem::Requirement
62
- none: false
63
65
  requirements:
64
- - - ! '>='
66
+ - - ">="
65
67
  - !ruby/object:Gem::Version
66
- version: '0'
67
- required_rubygems_version: !ruby/object:Gem::Requirement
68
+ segments:
69
+ - 0
70
+ version: !binary |-
71
+ MA==
72
+ hash: 2
68
73
  none: false
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
75
  requirements:
70
- - - ! '>='
76
+ - - ">="
71
77
  - !ruby/object:Gem::Version
72
- version: '0'
78
+ segments:
79
+ - 0
80
+ version: !binary |-
81
+ MA==
82
+ hash: 2
83
+ none: false
73
84
  requirements: []
74
- rubyforge_project:
75
- rubygems_version: 1.8.23
76
- signing_key:
85
+ rubyforge_project:
86
+ rubygems_version: 1.8.24
87
+ signing_key:
77
88
  specification_version: 3
78
89
  summary: Subexec spawns a subprocess with an optional timeout
79
90
  test_files: []
80
- has_rdoc: