net-ssh-shell 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.swp
2
+ pkg
3
+ doc
4
+ Gemfile.lock
@@ -0,0 +1,10 @@
1
+ ## 0.2.0 (unreleased)
2
+
3
+ - Loosen regex on `on_stdout` [GH-1]
4
+ - Capture stderr from shell. This won't capture the stderr of the processes
5
+ running. Instead it will just capture any error output from the shell process.
6
+ - Ability to specify the default process class to use for `Shell#execute`
7
+
8
+ ## 0.1.0 (October 24, 2010)
9
+
10
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "net-ssh-shell", :path => '.'
@@ -41,12 +41,12 @@ If you want to use any of the Rake tasks, you'll need:
41
41
  * Echoe (for the Rakefile)
42
42
 
43
43
  == INSTALL:
44
- This gem is not yet on rubygems , so you have to install it from this source
44
+
45
+ This gem is available from RubyGems, so you can install it using the "gem" command:
45
46
 
46
47
  * gem install net-ssh-shell
47
- ERROR: could not find gem net-ssh-shell locally or in a repository
48
48
 
49
- Therefor you need to build the gem yourself:
49
+ If you'd like to build the gem for yourself from source:
50
50
  * git clone http://github.com/jedi4ever/net-ssh-shell.git
51
51
  * cd net-ssh-shell
52
52
  * gem install echoe
data/Rakefile CHANGED
@@ -1,28 +1,3 @@
1
- require './lib/net/ssh/shell/version'
2
-
3
- begin
4
- require 'echoe'
5
- rescue LoadError
6
- abort "You'll need to have `echoe' installed to use Net::SSH::Shell's Rakefile"
7
- end
8
-
9
- version = Net::SSH::Shell::Version::STRING.dup
10
- if ENV['SNAPSHOT'].to_i == 1
11
- version << "." << Time.now.utc.strftime("%Y%m%d%H%M%S")
12
- end
13
-
14
- Echoe.new('net-ssh-shell', version) do |p|
15
- p.changelog = "CHANGELOG.rdoc"
16
-
17
- p.author = "Jamis Buck"
18
- p.email = "jamis@jamisbuck.org"
19
- p.summary = "A simple library to aid with stateful shell interactions"
20
- p.url = "http://net-ssh.rubyforge.org/shell"
21
-
22
- p.dependencies = ["net-ssh >=2.0.9"]
23
-
24
- p.need_zip = true
25
- p.include_rakefile = true
26
-
27
- p.rdoc_pattern = /^(lib|README.rdoc|CHANGELOG.rdoc)/
28
- end
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ Bundler::GemHelper.install_tasks
@@ -11,6 +11,7 @@ module Net
11
11
  attr_reader :state
12
12
  attr_reader :shell
13
13
  attr_reader :processes
14
+ attr_accessor :default_process_class
14
15
 
15
16
  def initialize(session, shell=:default)
16
17
  @session = session
@@ -18,6 +19,8 @@ module Net
18
19
  @state = :closed
19
20
  @processes = []
20
21
  @when_open = []
22
+ @on_process_run = nil
23
+ @default_process_class = Net::SSH::Shell::Process
21
24
  open
22
25
  end
23
26
 
@@ -26,6 +29,7 @@ module Net
26
29
  @state = :opening
27
30
  @channel = session.open_channel(&method(:open_succeeded))
28
31
  @channel.on_open_failed(&method(:open_failed))
32
+ @channel.on_request('exit-status', &method(:on_exit_status))
29
33
  end
30
34
  when_open(&callback) if callback
31
35
  self
@@ -60,11 +64,23 @@ module Net
60
64
  !open? && !closed?
61
65
  end
62
66
 
63
- def execute(command, klass=Net::SSH::Shell::Process, &callback)
64
- process = klass.new(self, command, callback)
65
- process.run if processes.empty?
67
+ def on_process_run(&callback)
68
+ @on_process_run = callback
69
+ end
70
+
71
+ def execute(command, *args, &callback)
72
+ # The class is an optional second argument.
73
+ klass = default_process_class
74
+ klass = args.shift if args.first.is_a?(Class)
75
+
76
+ # The properties are expected to be the next argument.
77
+ props = {}
78
+ props = args.shift if args.first.is_a?(Hash)
79
+
80
+ process = klass.new(self, command, props, callback)
66
81
  processes << process
67
- return process
82
+ run_next_process if processes.length == 1
83
+ process
68
84
  end
69
85
 
70
86
  def subshell(command, &callback)
@@ -72,9 +88,9 @@ module Net
72
88
  end
73
89
 
74
90
  def execute!(command, &callback)
75
- execute(command, &callback)
91
+ process = execute(command, &callback)
76
92
  wait!
77
- return process
93
+ process
78
94
  end
79
95
 
80
96
  def busy?
@@ -92,7 +108,7 @@ module Net
92
108
  def child_finished(child)
93
109
  channel.on_close(&method(:on_channel_close)) if !channel.nil?
94
110
  processes.delete(child)
95
- processes.first.run if processes.any?
111
+ run_next_process
96
112
  end
97
113
 
98
114
  def separator
@@ -109,41 +125,55 @@ module Net
109
125
 
110
126
  private
111
127
 
112
- def open_succeeded(channel)
113
- @state = :pty
114
- channel.on_close(&method(:on_channel_close))
115
- channel.request_pty(:modes => { Net::SSH::Connection::Term::ECHO => 0 }, &method(:pty_requested))
128
+ def run_next_process
129
+ if processes.any?
130
+ process = processes.first
131
+ @on_process_run.call(self, process) if @on_process_run
132
+ process.run
116
133
  end
134
+ end
117
135
 
118
- def open_failed(channel, code, description)
119
- @state = :closed
120
- raise "could not open channel for process manager (#{description}, ##{code})"
121
- end
136
+ def open_succeeded(channel)
137
+ @state = :pty
138
+ channel.on_close(&method(:on_channel_close))
139
+ channel.request_pty(:modes => { Net::SSH::Connection::Term::ECHO => 0 }, &method(:pty_requested))
140
+ end
141
+
142
+ def open_failed(channel, code, description)
143
+ @state = :closed
144
+ raise "could not open channel for process manager (#{description}, ##{code})"
145
+ end
122
146
 
123
- def pty_requested(channel, success)
124
- @state = :shell
125
- raise "could not request pty for process manager" unless success
126
- if shell == :default
127
- channel.send_channel_request("shell", &method(:shell_requested))
128
- else
129
- channel.exec(shell, &method(:shell_requested))
130
- end
147
+ def on_exit_status(channel, data)
148
+ unless data.read_long == 0
149
+ raise "the shell exited unexpectedly"
131
150
  end
151
+ end
132
152
 
133
- def shell_requested(channel, success)
134
- @state = :initializing
135
- raise "could not request shell for process manager" unless success
136
- channel.on_data(&method(:look_for_initialization_done))
137
- channel.send_data "export PS1=; echo #{separator} $?\n"
153
+ def pty_requested(channel, success)
154
+ @state = :shell
155
+ raise "could not request pty for process manager" unless success
156
+ if shell == :default
157
+ channel.send_channel_request("shell", &method(:shell_requested))
158
+ else
159
+ channel.exec(shell, &method(:shell_requested))
138
160
  end
161
+ end
162
+
163
+ def shell_requested(channel, success)
164
+ @state = :initializing
165
+ raise "could not request shell for process manager" unless success
166
+ channel.on_data(&method(:look_for_initialization_done))
167
+ channel.send_data "export PS1=; echo #{separator} $?\n"
168
+ end
139
169
 
140
- def look_for_initialization_done(channel, data)
141
- if data.include?(separator)
142
- @state = :open
143
- @when_open.each { |callback| callback.call(self) }
144
- @when_open.clear
145
- end
170
+ def look_for_initialization_done(channel, data)
171
+ if data.include?(separator)
172
+ @state = :open
173
+ @when_open.each { |callback| callback.call(self) }
174
+ @when_open.clear
146
175
  end
176
+ end
147
177
  end
148
178
  end
149
179
  end
@@ -155,6 +185,6 @@ class Net::SSH::Connection::Session
155
185
  def shell(*args)
156
186
  shell = Net::SSH::Shell.new(self, *args)
157
187
  yield shell if block_given?
158
- return shell
188
+ shell
159
189
  end
160
190
  end
@@ -1,5 +1,4 @@
1
1
  module Net; module SSH; class Shell
2
-
3
2
  class Process
4
3
  attr_reader :state
5
4
  attr_reader :command
@@ -8,12 +7,13 @@ module Net; module SSH; class Shell
8
7
  attr_reader :exit_status
9
8
  attr_reader :properties
10
9
 
11
- def initialize(manager, command, callback)
10
+ def initialize(manager, command, properties, callback)
12
11
  @command = command
13
12
  @manager = manager
14
13
  @callback = callback
15
- @properties = {}
16
- @on_output = Proc.new { |p, data| print(data) }
14
+ @properties = properties
15
+ @on_output = nil
16
+ @on_error_output = nil
17
17
  @on_finish = nil
18
18
  @state = :new
19
19
  end
@@ -36,14 +36,16 @@ module Net; module SSH; class Shell
36
36
  manager.open do
37
37
  state = :running
38
38
  manager.channel.on_data(&method(:on_stdout))
39
- @master_onclose = manager.channel.on_close(&method(:on_close))
39
+ manager.channel.on_extended_data(&method(:on_stderr))
40
+ manager.channel.on_close(&method(:on_close))
41
+
42
+ callback.call(self) if callback
40
43
 
41
44
  cmd = command.dup
42
45
  cmd << ";" if cmd !~ /[;&]$/
43
46
  cmd << " DONTEVERUSETHIS=$?; echo #{manager.separator} $DONTEVERUSETHIS; echo \"exit $DONTEVERUSETHIS\"|sh"
44
47
 
45
48
  send_data(cmd + "\n")
46
- callback.call(self) if callback
47
49
  end
48
50
  end
49
51
 
@@ -75,38 +77,44 @@ module Net; module SSH; class Shell
75
77
  @on_output = callback
76
78
  end
77
79
 
80
+ def on_error_output(&callback)
81
+ @on_error_output = callback
82
+ end
83
+
78
84
  def on_finish(&callback)
79
85
  @on_finish = callback
80
86
  end
81
87
 
82
- private
88
+ protected
83
89
 
84
- def output!(data)
85
- return unless @on_output
86
- @on_output.call(self, data)
87
- end
90
+ def output!(data)
91
+ @on_output.call(self, data) if @on_output
92
+ end
88
93
 
89
- def on_stdout(ch, data)
90
- if data.strip =~ /^#{manager.separator} (\d+)$/
91
- before = $`
92
- output!(before) unless before.empty?
93
- finished!($1)
94
- else
95
- output!(data)
96
- end
94
+ def on_stdout(ch, data)
95
+ if data.strip =~ /#{manager.separator} (\d+)$/
96
+ before = $`
97
+ output!(before) unless before.empty?
98
+ finished!($1)
99
+ else
100
+ output!(data)
97
101
  end
102
+ end
98
103
 
99
- def on_close(ch)
100
- manager.on_channel_close(ch)
101
- finished!(-1)
102
- end
104
+ def on_stderr(ch, type, data)
105
+ @on_error_output.call(self, data) if @on_error_output
106
+ end
103
107
 
104
- def finished!(status)
105
- @state = :finished
106
- @exit_status = status.to_i
107
- @on_finish.call(self) if @on_finish
108
- manager.child_finished(self)
109
- end
110
- end
108
+ def on_close(ch)
109
+ manager.on_channel_close(ch)
110
+ finished!(-1)
111
+ end
111
112
 
113
+ def finished!(status)
114
+ @state = :finished
115
+ @exit_status = status.to_i
116
+ @on_finish.call(self) if @on_finish
117
+ manager.child_finished(self)
118
+ end
119
+ end
112
120
  end; end; end
@@ -1,23 +1,21 @@
1
1
  require 'net/ssh/shell/process'
2
2
 
3
3
  module Net; module SSH; class Shell
4
-
5
4
  class Subshell < Process
6
- private
5
+ protected
7
6
 
8
- def on_stdout(ch, data)
9
- if !output!(data)
10
- ch.on_data(&method(:look_for_finalize_initializer))
11
- ch.send_data("export PS1=; echo #{manager.separator} $?\n")
12
- end
7
+ def on_stdout(ch, data)
8
+ if !output!(data)
9
+ ch.on_data(&method(:look_for_finalize_initializer))
10
+ ch.send_data("export PS1=; echo #{manager.separator} $?\n")
13
11
  end
12
+ end
14
13
 
15
- def look_for_finalize_initializer(ch, data)
16
- if data =~ /#{manager.separator} (\d+)/
17
- ch.on_close(&@master_onclose)
18
- finished!($1)
19
- end
14
+ def look_for_finalize_initializer(ch, data)
15
+ if data =~ /#{manager.separator} (\d+)/
16
+ ch.on_close(&@master_onclose)
17
+ finished!($1)
20
18
  end
19
+ end
21
20
  end
22
-
23
- end; end; end
21
+ end; end; end
@@ -1,22 +1,7 @@
1
- require 'net/ssh/version'
2
-
3
- module Net; module SSH; module Shell
4
- # A trivial class for representing the version of this library.
5
- class Version < Net::SSH::Version
6
- # The major component of the library's version
7
- MAJOR = 0
8
-
9
- # The minor component of the library's version
10
- MINOR = 1
11
-
12
- # The tiny component of the library's version
13
- TINY = 0
14
-
15
- # The library's version as a Version instance
16
- CURRENT = new(MAJOR, MINOR, TINY)
17
-
18
- # The library's version as a String instance
19
- STRING = CURRENT.to_s
1
+ module Net
2
+ module SSH
3
+ class Shell
4
+ VERSION = "0.2.0"
5
+ end
20
6
  end
21
- end; end; end
22
-
7
+ end
@@ -1,33 +1,23 @@
1
- # -*- encoding: utf-8 -*-
1
+ require File.expand_path("../lib/net/ssh/shell/version", __FILE__)
2
2
 
3
3
  Gem::Specification.new do |s|
4
- s.name = %q{net-ssh-shell}
5
- s.version = "0.1.0"
4
+ s.name = "net-ssh-shell"
5
+ s.version = Net::SSH::Shell::VERSION
6
+ s.platform = Gem::Platform::RUBY
7
+ s.authors = ["Jamis Buck"]
8
+ s.email = ["jamis@jamisbuck.org"]
9
+ s.homepage = "http://github.com/mitchellh/net-ssh-shell"
10
+ s.summary = "A simple library to aid with stateful shell interactions"
11
+ s.description = "A simple library to aid with stateful shell interactions"
6
12
 
7
- s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
- s.authors = ["Jamis Buck"]
9
- s.date = %q{2010-10-25}
10
- s.description = %q{A simple library to aid with stateful shell interactions}
11
- s.email = %q{jamis@jamisbuck.org}
12
- s.extra_rdoc_files = ["CHANGELOG.rdoc", "lib/net/ssh/shell/process.rb", "lib/net/ssh/shell/subshell.rb", "lib/net/ssh/shell/version.rb", "lib/net/ssh/shell.rb", "README.rdoc"]
13
- s.files = ["CHANGELOG.rdoc", "lib/net/ssh/shell/process.rb", "lib/net/ssh/shell/subshell.rb", "lib/net/ssh/shell/version.rb", "lib/net/ssh/shell.rb", "Rakefile", "README.rdoc", "Manifest", "net-ssh-shell.gemspec"]
14
- s.homepage = %q{http://net-ssh.rubyforge.org/shell}
15
- s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Net-ssh-shell", "--main", "README.rdoc"]
16
- s.require_paths = ["lib"]
17
- s.rubyforge_project = %q{net-ssh-shell}
18
- s.rubygems_version = %q{1.3.7}
19
- s.summary = %q{A simple library to aid with stateful shell interactions}
13
+ s.required_rubygems_version = ">= 1.3.6"
14
+ s.rubyforge_project = "net-ssh-shell"
20
15
 
21
- if s.respond_to? :specification_version then
22
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
- s.specification_version = 3
16
+ s.add_dependency "net-ssh", "~> 2.1.0"
24
17
 
25
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
- s.add_runtime_dependency(%q<net-ssh>, [">= 2.0.9"])
27
- else
28
- s.add_dependency(%q<net-ssh>, [">= 2.0.9"])
29
- end
30
- else
31
- s.add_dependency(%q<net-ssh>, [">= 2.0.9"])
32
- end
18
+ s.add_development_dependency "rake"
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
22
+ s.require_path = 'lib'
33
23
  end
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-ssh-shell
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 1
9
- - 0
10
- version: 0.1.0
4
+ prerelease:
5
+ version: 0.2.0
11
6
  platform: ruby
12
7
  authors:
13
8
  - Jamis Buck
@@ -15,60 +10,56 @@ autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
12
 
18
- date: 2010-10-25 00:00:00 +04:00
19
- default_executable:
13
+ date: 2011-06-13 00:00:00 Z
20
14
  dependencies:
21
15
  - !ruby/object:Gem::Dependency
22
16
  name: net-ssh
23
- prerelease: false
24
17
  requirement: &id001 !ruby/object:Gem::Requirement
25
18
  none: false
26
19
  requirements:
27
- - - ">="
20
+ - - ~>
28
21
  - !ruby/object:Gem::Version
29
- hash: 29
30
- segments:
31
- - 2
32
- - 0
33
- - 9
34
- version: 2.0.9
22
+ version: 2.1.0
35
23
  type: :runtime
24
+ prerelease: false
36
25
  version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: &id002 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *id002
37
37
  description: A simple library to aid with stateful shell interactions
38
- email: jamis@jamisbuck.org
38
+ email:
39
+ - jamis@jamisbuck.org
39
40
  executables: []
40
41
 
41
42
  extensions: []
42
43
 
43
- extra_rdoc_files:
44
- - CHANGELOG.rdoc
45
- - lib/net/ssh/shell/process.rb
46
- - lib/net/ssh/shell/subshell.rb
47
- - lib/net/ssh/shell/version.rb
48
- - lib/net/ssh/shell.rb
49
- - README.rdoc
44
+ extra_rdoc_files: []
45
+
50
46
  files:
51
- - CHANGELOG.rdoc
47
+ - .gitignore
48
+ - CHANGELOG.md
49
+ - Gemfile
50
+ - README.rdoc
51
+ - Rakefile
52
+ - lib/net/ssh/shell.rb
52
53
  - lib/net/ssh/shell/process.rb
53
54
  - lib/net/ssh/shell/subshell.rb
54
55
  - lib/net/ssh/shell/version.rb
55
- - lib/net/ssh/shell.rb
56
- - Rakefile
57
- - README.rdoc
58
- - Manifest
59
56
  - net-ssh-shell.gemspec
60
- has_rdoc: true
61
- homepage: http://net-ssh.rubyforge.org/shell
57
+ homepage: http://github.com/mitchellh/net-ssh-shell
62
58
  licenses: []
63
59
 
64
60
  post_install_message:
65
- rdoc_options:
66
- - --line-numbers
67
- - --inline-source
68
- - --title
69
- - Net-ssh-shell
70
- - --main
71
- - README.rdoc
61
+ rdoc_options: []
62
+
72
63
  require_paths:
73
64
  - lib
74
65
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -76,7 +67,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
67
  requirements:
77
68
  - - ">="
78
69
  - !ruby/object:Gem::Version
79
- hash: 3
70
+ hash: -9612031956568265
80
71
  segments:
81
72
  - 0
82
73
  version: "0"
@@ -85,15 +76,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
76
  requirements:
86
77
  - - ">="
87
78
  - !ruby/object:Gem::Version
88
- hash: 11
89
- segments:
90
- - 1
91
- - 2
92
- version: "1.2"
79
+ version: 1.3.6
93
80
  requirements: []
94
81
 
95
82
  rubyforge_project: net-ssh-shell
96
- rubygems_version: 1.3.7
83
+ rubygems_version: 1.8.5
97
84
  signing_key:
98
85
  specification_version: 3
99
86
  summary: A simple library to aid with stateful shell interactions
@@ -1,3 +0,0 @@
1
- === (unreleased)
2
-
3
- * Initial release
data/Manifest DELETED
@@ -1,8 +0,0 @@
1
- CHANGELOG.rdoc
2
- lib/net/ssh/shell/process.rb
3
- lib/net/ssh/shell/subshell.rb
4
- lib/net/ssh/shell/version.rb
5
- lib/net/ssh/shell.rb
6
- Rakefile
7
- README.rdoc
8
- Manifest