subexec 0.0.1
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.rdoc +29 -0
- data/VERSION +1 -0
- data/lib/subexec.rb +86 -0
- metadata +70 -0
data/README.rdoc
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
= Subexec
|
2
|
+
by Peter Kieltyka
|
3
|
+
http://github/nulayer/subexec
|
4
|
+
|
5
|
+
=== Description
|
6
|
+
|
7
|
+
Subexec is a simple library that spawns an external command with
|
8
|
+
an optional timeout parameter. It relies on Ruby 1.9's Process.spawn
|
9
|
+
method. Also, it works with synchronous and asynchronous code.
|
10
|
+
|
11
|
+
Useful for libraries that are Ruby wrappers for CLI's. For example,
|
12
|
+
resizing images with ImageMagick's mogrify command sometimes stalls
|
13
|
+
and never returns control back to the original process. Enter Subexec.
|
14
|
+
|
15
|
+
=== Usage
|
16
|
+
|
17
|
+
sub = Subexec.run "echo 'hello' && sleep 3", :timeout => 5
|
18
|
+
puts sub.output # returns: hello
|
19
|
+
puts sub.exitstatus # returns: 0
|
20
|
+
|
21
|
+
sub = Subexec.run "echo 'hello' && sleep 3", :timeout => 1
|
22
|
+
puts sub.output # returns:
|
23
|
+
puts sub.exitstatus # returns:
|
24
|
+
|
25
|
+
|
26
|
+
=== Limitations
|
27
|
+
|
28
|
+
Supports only Ruby 1.9.
|
29
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/lib/subexec.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# = Subexec
|
2
|
+
# * by Peter Kieltyka
|
3
|
+
# * http://github/nulayer/subprocess
|
4
|
+
#
|
5
|
+
# === Description
|
6
|
+
#
|
7
|
+
# Subexec is a simple library that spawns an external command with
|
8
|
+
# an optional timeout parameter. It relies on Ruby 1.9's Process.spawn
|
9
|
+
# method. Also, it works with synchronous and asynchronous code.
|
10
|
+
#
|
11
|
+
# Useful for libraries that are Ruby wrappers for CLI's. For example,
|
12
|
+
# resizing images with ImageMagick's mogrify command sometimes stalls
|
13
|
+
# and never returns control back to the original process. Subexec
|
14
|
+
# executes mogrify and preempts if gets lost.
|
15
|
+
#
|
16
|
+
# === Usage
|
17
|
+
#
|
18
|
+
# # Print hello
|
19
|
+
# sub = Subexec.run "echo 'hello' && sleep 3", :timeout => 5
|
20
|
+
# puts sub.output # returns: hello
|
21
|
+
# puts sub.exitstatus # returns: 0
|
22
|
+
#
|
23
|
+
# # Timeout process after a second
|
24
|
+
# sub = Subexec.run "echo 'hello' && sleep 3", :timeout => 1
|
25
|
+
# puts sub.output # returns:
|
26
|
+
# puts sub.exitstatus # returns:
|
27
|
+
|
28
|
+
class Subexec
|
29
|
+
|
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
|
+
|
37
|
+
def self.run(command, options={})
|
38
|
+
new(command, options)
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(command, options={})
|
42
|
+
self.command = command
|
43
|
+
self.timeout = options[:timeout] || -1 # default is to never timeout
|
44
|
+
run!
|
45
|
+
end
|
46
|
+
|
47
|
+
def run!
|
48
|
+
r, w = IO.pipe
|
49
|
+
self.pid = Process.spawn(command, STDERR=>STDOUT, STDOUT=>w)
|
50
|
+
w.close
|
51
|
+
|
52
|
+
self.timer = Time.now + timeout
|
53
|
+
timed_out = false
|
54
|
+
|
55
|
+
loop do
|
56
|
+
begin
|
57
|
+
flags = (timeout > 0 ? Process::WUNTRACED|Process::WNOHANG : 0)
|
58
|
+
ret = Process.waitpid(pid, flags)
|
59
|
+
rescue Errno::ECHILD
|
60
|
+
break
|
61
|
+
end
|
62
|
+
|
63
|
+
break if ret == pid
|
64
|
+
sleep 0.001
|
65
|
+
if Time.now > timer
|
66
|
+
timed_out = true
|
67
|
+
break
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if timed_out
|
72
|
+
# The subprocess timed out -- kill it
|
73
|
+
Process.kill(9, pid) rescue Errno::ESRCH
|
74
|
+
self.exitstatus = nil
|
75
|
+
else
|
76
|
+
# The subprocess exited on its own
|
77
|
+
self.exitstatus = $?.exitstatus
|
78
|
+
self.output = r.readlines.join("")
|
79
|
+
end
|
80
|
+
r.close
|
81
|
+
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: subexec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Peter Kieltyka
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-05-24 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Subexec spawns an external command with a timeout
|
23
|
+
email:
|
24
|
+
- peter@nulayer.com
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- README.rdoc
|
33
|
+
- VERSION
|
34
|
+
- lib/subexec.rb
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: http://github.com/nulayer/subexec
|
37
|
+
licenses: []
|
38
|
+
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
hash: 3
|
50
|
+
segments:
|
51
|
+
- 0
|
52
|
+
version: "0"
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.3.7
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Subexec spawns an external command with a timeout
|
69
|
+
test_files: []
|
70
|
+
|