blue_shell 0.6 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,14 +9,33 @@ module BlueShell
9
9
 
10
10
  attr_reader :out, :err, :exit
11
11
 
12
+ def initialize
13
+ @hooks = { stderr: [], stdout: [] }
14
+ @executing = false
15
+ end
16
+
17
+ # Add a lambda to execute on every line of stdout. The lambda
18
+ # should accept one parameter, a string, the line of output.
19
+ # @example Pushing to the console
20
+ # lambda { |line| puts line }
21
+ # @param [Symbol] the stream to hook into (:stderr or :stdout)
22
+ # @param [Lambda] the code to execute
23
+ def add_hook(type, lambda)
24
+ # TODO: This should be a custom error
25
+ raise "May not add hooks while executing." if @executing
26
+
27
+ @hooks[type] << lambda
28
+ end
29
+
12
30
  # Execute the given command. Will block until the command completes.
13
31
  # param [String] the command to execute in bash
14
32
  # param [Integer] the number of seconds to wait for it to complete
15
33
  def execute!(command, timeout = 30)
16
- # Executing via a file seems clunky, but it is the best way to
34
+ # Executing via a file seems clunky, but it is a good way to
17
35
  # ensure everything happens exactly as we expect it to without
18
36
  # trying to deal with escaping the world properly.
19
37
  file = Tempfile.new('command')
38
+
20
39
  begin
21
40
  file << command
22
41
  file.flush
@@ -28,8 +47,8 @@ module BlueShell
28
47
  @err = []
29
48
 
30
49
  # Must have a sink for stdout for the proc to exit
31
- out_thread = read_thread(proc.getInputStream, @out)
32
- err_thread = read_thread(proc.getErrorStream, @err)
50
+ out_thread = read_thread(:stdout, proc.getInputStream, @out)
51
+ err_thread = read_thread(:stderr, proc.getErrorStream, @err)
33
52
 
34
53
  out_thread.join
35
54
  err_thread.join
@@ -37,6 +56,9 @@ module BlueShell
37
56
  @out = @out.join("\n")
38
57
  @err = @err.join("\n")
39
58
 
59
+ # Noticed some cases where the join isn't good enough in the wild.
60
+ proc.waitFor
61
+
40
62
  @exit = proc.exitValue
41
63
  end
42
64
  ensure
@@ -45,13 +67,14 @@ module BlueShell
45
67
  end
46
68
  end
47
69
 
48
- def read_thread(stream, sink)
49
- Thread.new(stream, sink) do |stream, sink|
70
+ def read_thread(type, stream, sink)
71
+ Thread.new(@hooks[type], stream, sink) do |hooks, stream, sink|
50
72
  line = nil
51
73
  br = BufferedReader.new(InputStreamReader.new(stream))
52
74
 
53
75
  while(line = br.readLine) do
54
76
  sink << line
77
+ hooks.each { |hook| hook.call(line) }
55
78
  end
56
79
  end
57
80
  end
@@ -1,3 +1,3 @@
1
1
  module BlueShell
2
- VERSION = "0.6"
2
+ VERSION = "0.7"
3
3
  end
@@ -25,4 +25,20 @@ describe BlueShell::Bash do
25
25
  @shell.execute!("ls -l /")
26
26
  @shell.out.must_include "\n"
27
27
  end
28
+
29
+ it "should execute stdout hooks" do
30
+ me = nil
31
+
32
+ @shell.add_hook(:stdout, lambda { |line| me = line })
33
+ @shell.execute!("echo hello")
34
+ me.must_equal "hello"
35
+ end
36
+
37
+ it "should execute stderr hooks" do
38
+ me = nil
39
+
40
+ @shell.add_hook(:stderr, lambda { |line| me = line })
41
+ @shell.execute!("omg")
42
+ me.must_include "omg: command not found"
43
+ end
28
44
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blue_shell
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.6'
4
+ version: '0.7'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-07 00:00:00.000000000 Z
12
+ date: 2012-11-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest