rush 0.3 → 0.4

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/Rakefile CHANGED
@@ -31,7 +31,7 @@ require 'rake/rdoctask'
31
31
  require 'fileutils'
32
32
  include FileUtils
33
33
 
34
- version = "0.3"
34
+ version = "0.4"
35
35
  name = "rush"
36
36
 
37
37
  spec = Gem::Specification.new do |s|
data/bin/rush CHANGED
@@ -3,5 +3,11 @@
3
3
  require File.dirname(__FILE__) + '/../lib/rush'
4
4
  require File.dirname(__FILE__) + '/../lib/rush/shell'
5
5
 
6
- Rush::Shell.new.run
6
+ shell = Rush::Shell.new
7
+
8
+ if ARGV.size > 0
9
+ shell.execute ARGV.join(' ')
10
+ else
11
+ shell.run
12
+ end
7
13
 
data/bin/rushd CHANGED
File without changes
@@ -19,6 +19,7 @@ require 'rush/string_ext'
19
19
  require 'rush/fixnum_ext'
20
20
  require 'rush/array_ext'
21
21
  require 'rush/process'
22
+ require 'rush/process_set'
22
23
  require 'rush/local'
23
24
  require 'rush/remote'
24
25
  require 'rush/ssh_tunnel'
@@ -41,26 +41,39 @@ class Rush::Box
41
41
  filesystem[key]
42
42
  end
43
43
 
44
- # Get the list of processes currently running on the box. Returns an array
45
- # of Rush::Process.
44
+ # Get the list of processes running on the box, not unlike "ps aux" in bash.
45
+ # Returns a Rush::ProcessSet.
46
46
  def processes
47
- connection.processes.map do |ps|
48
- Rush::Process.new(ps, self)
49
- end
47
+ Rush::ProcessSet.new(
48
+ connection.processes.map do |ps|
49
+ Rush::Process.new(ps, self)
50
+ end
51
+ )
50
52
  end
51
53
 
52
- # Execute a command in the standard unix shell. Options:
54
+ # Execute a command in the standard unix shell. Returns the contents of
55
+ # stdout if successful, or raises Rush::BashFailed with the output of stderr
56
+ # if the shell returned a non-zero value. Options:
53
57
  #
54
58
  # :user => unix username to become via sudo
55
59
  # :env => hash of environment variables
60
+ # :background => run in the background (returns Rush::Process instead of stdout)
56
61
  #
57
- # Example:
62
+ # Examples:
58
63
  #
59
64
  # box.bash '/etc/init.d/mysql restart', :user => 'root'
60
65
  # box.bash 'rake db:migrate', :user => 'www', :env => { :RAILS_ENV => 'production' }
66
+ # box.bash 'mongrel_rails start', :background => true
61
67
  #
62
68
  def bash(command, options={})
63
- connection.bash(command_with_environment(command, options[:env]), options[:user])
69
+ cmd_with_env = command_with_environment(command, options[:env])
70
+
71
+ if options[:background]
72
+ pid = connection.bash(cmd_with_env, options[:user], true)
73
+ processes.find_by_pid(pid)
74
+ else
75
+ connection.bash(cmd_with_env, options[:user], false)
76
+ end
64
77
  end
65
78
 
66
79
  def command_with_environment(command, env) # :nodoc:
@@ -1,12 +1,14 @@
1
1
  module Rush
2
2
  # Base class for all rush exceptions.
3
- class Exception < ::Exception; end
3
+ class Exception < ::RuntimeError; end
4
4
 
5
5
  # Client was not authorized by remote server; check credentials.
6
6
  class NotAuthorized < Exception; end
7
7
 
8
- # Failed to transmit to the remote server; check if the ssh tunnel is alive,
9
- # and rushd is listening on the other end.
8
+ # rushd is not running on the remote box.
9
+ class RushdNotRunning < Exception; end
10
+
11
+ # An unrecognized status code was returned by rushd.
10
12
  class FailedTransmit < Exception; end
11
13
 
12
14
  # The entry (file or dir) referenced does not exist. Message is the entry's full path.
@@ -133,7 +133,7 @@ class Rush::Connection::Local
133
133
  # Get the list of processes as an array of hashes.
134
134
  def processes
135
135
  if ::File.directory? "/proc"
136
- linux_processes
136
+ resolve_unix_uids(linux_processes)
137
137
  elsif ::File.directory? "C:/WINDOWS"
138
138
  windows_processes
139
139
  else
@@ -154,6 +154,33 @@ class Rush::Connection::Local
154
154
  list
155
155
  end
156
156
 
157
+ def resolve_unix_uids(list)
158
+ @uid_map = {} # reset the cache between uid resolutions.
159
+ list.each do |process|
160
+ process[:user] = resolve_unix_uid_to_user(process[:uid])
161
+ end
162
+ list
163
+ end
164
+
165
+ # resolve uid to user
166
+ def resolve_unix_uid_to_user(uid)
167
+ require 'etc'
168
+
169
+ @uid_map ||= {}
170
+ uid = uid.to_i
171
+
172
+ return @uid_map[uid] if !@uid_map[uid].nil?
173
+
174
+ begin
175
+ record = Etc.getpwuid(uid)
176
+ rescue ArgumentError
177
+ return nil
178
+ end
179
+
180
+ @uid_map[uid] = record.name
181
+ @uid_map[uid]
182
+ end
183
+
157
184
  # Read a single file in /proc and store the parsed values in a hash suitable
158
185
  # for use in the Rush::Process#new.
159
186
  def read_proc_file(file)
@@ -256,15 +283,20 @@ class Rush::Connection::Local
256
283
  end
257
284
 
258
285
  ::Process.kill('KILL', pid) rescue nil
286
+
287
+ rescue Errno::ESRCH
288
+ # if it's dead, great - do nothing
259
289
  end
260
290
 
261
- def bash(command, user=nil)
291
+ def bash(command, user=nil, background=false)
292
+ return bash_background(command, user) if background
293
+
262
294
  require 'session'
263
295
 
264
296
  sh = Session::Bash.new
265
297
 
266
298
  if user and user != ""
267
- out, err = sh.execute "sudo -u #{user} bash", :stdin => command
299
+ out, err = sh.execute "cd /; sudo -H -u #{user} bash", :stdin => command
268
300
  else
269
301
  out, err = sh.execute command
270
302
  end
@@ -277,6 +309,27 @@ class Rush::Connection::Local
277
309
  out
278
310
  end
279
311
 
312
+ def bash_background(command, user)
313
+ inpipe, outpipe = IO.pipe
314
+
315
+ pid = fork do
316
+ outpipe.write command
317
+ outpipe.close
318
+ STDIN.reopen(inpipe)
319
+
320
+ if user and user != ''
321
+ exec "cd /; sudo -H -u #{user} bash"
322
+ else
323
+ exec "bash"
324
+ end
325
+ end
326
+ outpipe.close
327
+
328
+ Process::detach pid
329
+
330
+ pid
331
+ end
332
+
280
333
  ####################################
281
334
 
282
335
  # Raised when the action passed in by RushServer is not known.
@@ -304,7 +357,7 @@ class Rush::Connection::Local
304
357
  when 'processes' then YAML.dump(processes)
305
358
  when 'process_alive' then process_alive(params[:pid]) ? '1' : '0'
306
359
  when 'kill_process' then kill_process(params[:pid].to_i)
307
- when 'bash' then bash(params[:payload], params[:user])
360
+ when 'bash' then bash(params[:payload], params[:user], params[:background] == 'true')
308
361
  else
309
362
  raise UnknownAction
310
363
  end
@@ -1,6 +1,6 @@
1
1
  # An array of these objects is returned by Rush::Box#processes.
2
2
  class Rush::Process
3
- attr_reader :box, :pid, :uid, :parent_pid, :command, :cmdline, :mem, :cpu
3
+ attr_reader :box, :pid, :uid, :parent_pid, :command, :cmdline, :mem, :cpu, :user
4
4
 
5
5
  # params is a hash returned by the system-specific method of looking up the
6
6
  # process list.
@@ -9,6 +9,7 @@ class Rush::Process
9
9
 
10
10
  @pid = params[:pid].to_i
11
11
  @uid = params[:uid].to_i
12
+ @user = params[:user]
12
13
  @command = params[:command]
13
14
  @cmdline = params[:cmdline]
14
15
  @mem = params[:mem]
@@ -0,0 +1,62 @@
1
+ # A container for processes that behaves like an array, and adds process-specific operations
2
+ # on the entire set, like kill.
3
+ #
4
+ # Example:
5
+ #
6
+ # processes.filter(:cmdline => /mongrel_rails/).kill
7
+ #
8
+ class Rush::ProcessSet
9
+ attr_reader :processes
10
+
11
+ def initialize(processes)
12
+ @processes = processes
13
+ end
14
+
15
+ # Filter by any field that the process responds to. Specify an exact value,
16
+ # or a regular expression. All conditions are put together as a boolean
17
+ # AND, so these two statements are equivalent:
18
+ #
19
+ # processes.filter(:uid => 501).filter(:cmdline => /ruby/)
20
+ # processes.filter(:uid => 501, :cmdline => /ruby/)
21
+ #
22
+ def filter(conditions)
23
+ Rush::ProcessSet.new(
24
+ processes.select do |p|
25
+ conditions.all? do |key, value|
26
+ value.class == Regexp ?
27
+ value.match(p.send(key)) :
28
+ p.send(key) == value
29
+ end
30
+ end
31
+ )
32
+ end
33
+
34
+ # Kill all processes in the set.
35
+ def kill
36
+ processes.each { |p| p.kill }
37
+ end
38
+
39
+ # Check status of all processes in the set, returns an array of booleans.
40
+ def alive?
41
+ processes.map { |p| p.alive? }
42
+ end
43
+
44
+ include Enumerable
45
+
46
+ def each
47
+ processes.each { |p| yield p }
48
+ end
49
+
50
+ def ==(other)
51
+ if other.class == self.class
52
+ other.processes == processes
53
+ else
54
+ to_a == other
55
+ end
56
+ end
57
+
58
+ # All other messages (like size or first) are passed through to the array.
59
+ def method_missing(meth, *args)
60
+ processes.send(meth, *args)
61
+ end
62
+ end
@@ -63,7 +63,7 @@ class Rush::Connection::Remote
63
63
  end
64
64
 
65
65
  def size(full_path)
66
- transmit(:action => 'size', :full_path => full_path)
66
+ transmit(:action => 'size', :full_path => full_path).to_i
67
67
  end
68
68
 
69
69
  def processes
@@ -78,8 +78,8 @@ class Rush::Connection::Remote
78
78
  transmit(:action => 'kill_process', :pid => pid)
79
79
  end
80
80
 
81
- def bash(command, user)
82
- transmit(:action => 'bash', :payload => command, :user => user)
81
+ def bash(command, user, background)
82
+ transmit(:action => 'bash', :payload => command, :user => user, :background => background)
83
83
  end
84
84
 
85
85
  # Given a hash of parameters (converted by the method call on the connection
@@ -104,6 +104,8 @@ class Rush::Connection::Remote
104
104
  res = http.request(req, payload)
105
105
  process_result(res.code, res.body)
106
106
  end
107
+ rescue EOFError
108
+ raise Rush::RushdNotRunning
107
109
  end
108
110
 
109
111
  # Take the http result of a transmit and raise an error, or return the body
@@ -31,6 +31,21 @@ module Rush
31
31
  Array.class_eval commands
32
32
  end
33
33
 
34
+ # Run a single command.
35
+ def execute(cmd)
36
+ res = eval(cmd, @pure_binding)
37
+ $last_res = res
38
+ eval("_ = $last_res", @pure_binding)
39
+ print_result res
40
+ rescue Rush::Exception => e
41
+ puts "Exception #{e.class} -> #{e.message}"
42
+ rescue ::Exception => e
43
+ puts "Exception #{e.class} -> #{e.message}"
44
+ e.backtrace.each do |t|
45
+ puts " #{::File.expand_path(t)}"
46
+ end
47
+ end
48
+
34
49
  # Run the interactive shell using readline.
35
50
  def run
36
51
  loop do
@@ -40,19 +55,7 @@ module Rush
40
55
  next if cmd == ""
41
56
  Readline::HISTORY.push(cmd)
42
57
 
43
- begin
44
- res = eval(cmd, @pure_binding)
45
- $last_res = res
46
- eval("_ = $last_res", @pure_binding)
47
- print_result res
48
- rescue Rush::Exception => e
49
- puts "Exception #{e.class} -> #{e.message}"
50
- rescue ::Exception => e
51
- puts "Exception #{e.class} -> #{e.message}"
52
- e.backtrace.each do |t|
53
- puts " #{::File.expand_path(t)}"
54
- end
55
- end
58
+ execute(cmd)
56
59
  end
57
60
  end
58
61
 
@@ -67,10 +70,6 @@ module Rush
67
70
  def print_result(res)
68
71
  if res.kind_of? String
69
72
  puts res
70
- elsif res.kind_of? Array
71
- res.each do |item|
72
- puts item
73
- end
74
73
  elsif res.kind_of? Rush::SearchResults
75
74
  widest = res.entries.map { |k| k.full_path.length }.max
76
75
  res.entries_with_lines.each do |entry, lines|
@@ -85,6 +84,21 @@ module Rush
85
84
  print "\n"
86
85
  end
87
86
  puts "#{res.entries.size} matching files with #{res.lines.size} matching lines"
87
+ elsif res.respond_to? :each
88
+ counts = {}
89
+ res.each do |item|
90
+ puts item
91
+ counts[item.class] ||= 0
92
+ counts[item.class] += 1
93
+ end
94
+ if counts == {}
95
+ puts "=> (empty set)"
96
+ else
97
+ count_s = counts.map do |klass, count|
98
+ "#{count} x #{klass}"
99
+ end.join(', ')
100
+ puts "=> #{count_s}"
101
+ end
88
102
  else
89
103
  puts "=> #{res.inspect}"
90
104
  end
@@ -22,15 +22,21 @@ describe Rush::Box do
22
22
  end
23
23
 
24
24
  it "executes bash commands" do
25
- @box.connection.should_receive(:bash).with('cmd', nil).and_return('output')
25
+ @box.connection.should_receive(:bash).with('cmd', nil, false).and_return('output')
26
26
  @box.bash('cmd').should == 'output'
27
27
  end
28
28
 
29
29
  it "executes bash commands with an optional user" do
30
- @box.connection.should_receive(:bash).with('cmd', 'user')
30
+ @box.connection.should_receive(:bash).with('cmd', 'user', false)
31
31
  @box.bash('cmd', :user => 'user')
32
32
  end
33
33
 
34
+ it "executes bash commands in the background, returning a Rush::Process" do
35
+ @box.connection.should_receive(:bash).with('cmd', nil, true).and_return(123)
36
+ @box.stub!(:processes).and_return([ mock('ps', :pid => 123) ])
37
+ @box.bash('cmd', :background => true).pid.should == 123
38
+ end
39
+
34
40
  it "builds a script of environment variables to prefix the bash command" do
35
41
  @box.command_with_environment('cmd', { :a => 'b' }).should == "export a='b'\ncmd"
36
42
  end
@@ -152,8 +152,8 @@ describe Rush::Dir do
152
152
  end
153
153
 
154
154
  it "passes bash options (e.g., :user) through to the box bash command" do
155
- @box.should_receive(:bash).with('cmd', 'options')
156
- @box.bash('cmd', 'options')
155
+ @box.should_receive(:bash).with('cmd', :opt1 => 1, :opt2 => 2)
156
+ @box.bash('cmd', :opt1 => 1, :opt2 => 2)
157
157
  end
158
158
 
159
159
  end
@@ -95,9 +95,14 @@ describe Rush::Connection::Local do
95
95
  @con.receive(:action => 'kill_process', :pid => '123')
96
96
  end
97
97
 
98
- it "receive -> bash" do
99
- @con.should_receive(:bash).with('cmd', 'user').and_return('output')
100
- @con.receive(:action => 'bash', :payload => 'cmd', :user => 'user').should == 'output'
98
+ it "receive -> bash (foreground)" do
99
+ @con.should_receive(:bash).with('cmd', 'user', false).and_return('output')
100
+ @con.receive(:action => 'bash', :payload => 'cmd', :user => 'user', :background => 'false').should == 'output'
101
+ end
102
+
103
+ it "receive -> bash (background)" do
104
+ @con.should_receive(:bash).with('cmd', 'user', true).and_return('output')
105
+ @con.receive(:action => 'bash', :payload => 'cmd', :user => 'user', :background => 'true').should == 'output'
101
106
  end
102
107
 
103
108
  it "receive -> unknown action exception" do
@@ -263,6 +268,11 @@ EOPS
263
268
  @con.kill_process(123)
264
269
  end
265
270
 
271
+ it "does not raise an error if the process is already dead" do
272
+ ::Process.should_receive(:kill).and_raise(Errno::ESRCH)
273
+ lambda { @con.kill_process(123) }.should_not raise_error
274
+ end
275
+
266
276
  it "executes a bash command, returning stdout when successful" do
267
277
  @con.bash("echo test").should == "test\n"
268
278
  end
@@ -272,7 +282,11 @@ EOPS
272
282
  end
273
283
 
274
284
  it "executes a bash command as another user using sudo" do
275
- @con.bash("echo test2", ENV['user']).should == "test2\n"
285
+ @con.bash("echo test2", ENV['USER']).should == "test2\n"
286
+ end
287
+
288
+ it "executes a bash command in the background, returning the pid" do
289
+ @con.bash("true", nil, true).should > 0
276
290
  end
277
291
 
278
292
  it "ensure_tunnel to match with remote connection" do
@@ -282,4 +296,18 @@ EOPS
282
296
  it "always returns true on alive?" do
283
297
  @con.should be_alive
284
298
  end
299
+
300
+ it "resolves a unix uid to a user" do
301
+ @con.resolve_unix_uid_to_user(0).should == "root"
302
+ @con.resolve_unix_uid_to_user('0').should == "root"
303
+ end
304
+
305
+ it "returns nil if the unix uid does not exist" do
306
+ @con.resolve_unix_uid_to_user(9999).should be_nil
307
+ end
308
+
309
+ it "iterates through a process list and resolves the unix uid for each" do
310
+ list = [ { :uid => 0, :command => 'pureftpd' }, { :uid => 9999, :command => 'defunk' } ]
311
+ @con.resolve_unix_uids(list).should == [ { :uid => 0, :user => 'root', :command => 'pureftpd' }, { :uid => 9999, :command => 'defunk', :user => nil } ]
312
+ end
285
313
  end
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Rush::ProcessSet do
4
+ before do
5
+ @process = mock('process')
6
+ @set = Rush::ProcessSet.new([ @process ])
7
+ end
8
+
9
+ it "is Enumerable" do
10
+ @set.select { |s| s == @process }.should == [ @process ]
11
+ end
12
+
13
+ it "defines size" do
14
+ @set.size.should == 1
15
+ end
16
+
17
+ it "defines first" do
18
+ @set.first.should == @process
19
+ end
20
+
21
+ it "is equal to sets with the same contents" do
22
+ @set.should == Rush::ProcessSet.new([ @process ])
23
+ end
24
+
25
+ it "is equal to arrays with the same contents" do
26
+ @set.should == [ @process ]
27
+ end
28
+
29
+ it "kills all processes in the set" do
30
+ @process.should_receive(:kill)
31
+ @set.kill
32
+ end
33
+
34
+ it "checks the alive? state of all processes in the set" do
35
+ @process.should_receive(:alive?).and_return(true)
36
+ @set.alive?.should == [ true ]
37
+ end
38
+
39
+ it "filters the set from a conditions hash and returns the filtered set" do
40
+ @process.stub!(:pid).and_return(123)
41
+ @set.filter(:pid => 123).first.should == @process
42
+ @set.filter(:pid => 456).size.should == 0
43
+ end
44
+
45
+ it "filters with regexps if provided in the conditions" do
46
+ @process.stub!(:command).and_return('foobaz')
47
+ @set.filter(:command => /baz/).first.should == @process
48
+ @set.filter(:command => /blerg/).size.should == 0
49
+ end
50
+ end
@@ -34,7 +34,7 @@ describe Rush::Process do
34
34
  end
35
35
 
36
36
  it "knows the executed binary" do
37
- @process.command.should == "ruby"
37
+ @process.command.should match(/^ruby/)
38
38
  end
39
39
 
40
40
  it "knows the command line" do
@@ -73,8 +73,8 @@ describe Rush::Connection::Local do
73
73
  end
74
74
 
75
75
  it "transmits size" do
76
- @con.should_receive(:transmit).with(:action => 'size', :full_path => 'full_path').and_return("")
77
- @con.size('full_path')
76
+ @con.should_receive(:transmit).with(:action => 'size', :full_path => 'full_path').and_return("123")
77
+ @con.size('full_path').should == 123
78
78
  end
79
79
 
80
80
  it "transmits processes" do
@@ -93,8 +93,8 @@ describe Rush::Connection::Local do
93
93
  end
94
94
 
95
95
  it "transmits bash" do
96
- @con.should_receive(:transmit).with(:action => 'bash', :payload => 'cmd', :user => 'user').and_return('output')
97
- @con.bash('cmd', 'user').should == 'output'
96
+ @con.should_receive(:transmit).with(:action => 'bash', :payload => 'cmd', :user => 'user', :background => 'bg').and_return('output')
97
+ @con.bash('cmd', 'user', 'bg').should == 'output'
98
98
  end
99
99
 
100
100
  it "an http result code of 401 raises NotAuthorized" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rush
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.3"
4
+ version: "0.4"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Wiggins
@@ -9,11 +9,12 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-03-26 00:00:00 -07:00
12
+ date: 2008-07-14 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: mongrel
17
+ type: :runtime
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
@@ -23,6 +24,7 @@ dependencies:
23
24
  version:
24
25
  - !ruby/object:Gem::Dependency
25
26
  name: rspec
27
+ type: :runtime
26
28
  version_requirement:
27
29
  version_requirements: !ruby/object:Gem::Requirement
28
30
  requirements:
@@ -32,6 +34,7 @@ dependencies:
32
34
  version:
33
35
  - !ruby/object:Gem::Dependency
34
36
  name: session
37
+ type: :runtime
35
38
  version_requirement:
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
@@ -52,46 +55,48 @@ files:
52
55
  - Rakefile
53
56
  - bin/rush
54
57
  - bin/rushd
58
+ - lib/rush.rb
55
59
  - lib/rush
56
- - lib/rush/access.rb
57
- - lib/rush/array_ext.rb
58
- - lib/rush/box.rb
59
- - lib/rush/commands.rb
60
60
  - lib/rush/config.rb
61
- - lib/rush/dir.rb
61
+ - lib/rush/head_tail.rb
62
+ - lib/rush/search_results.rb
62
63
  - lib/rush/entry.rb
63
- - lib/rush/exceptions.rb
64
- - lib/rush/file.rb
65
64
  - lib/rush/find_by.rb
66
- - lib/rush/fixnum_ext.rb
67
- - lib/rush/head_tail.rb
65
+ - lib/rush/file.rb
68
66
  - lib/rush/local.rb
69
- - lib/rush/process.rb
70
- - lib/rush/remote.rb
71
- - lib/rush/search_results.rb
72
- - lib/rush/server.rb
73
- - lib/rush/shell.rb
74
67
  - lib/rush/ssh_tunnel.rb
68
+ - lib/rush/shell.rb
69
+ - lib/rush/server.rb
70
+ - lib/rush/process_set.rb
71
+ - lib/rush/array_ext.rb
72
+ - lib/rush/remote.rb
73
+ - lib/rush/fixnum_ext.rb
74
+ - lib/rush/commands.rb
75
+ - lib/rush/process.rb
76
+ - lib/rush/dir.rb
75
77
  - lib/rush/string_ext.rb
76
- - lib/rush.rb
78
+ - lib/rush/box.rb
79
+ - lib/rush/exceptions.rb
80
+ - lib/rush/access.rb
81
+ - spec/remote_spec.rb
82
+ - spec/base.rb
83
+ - spec/ssh_tunnel_spec.rb
84
+ - spec/local_spec.rb
77
85
  - spec/access_spec.rb
86
+ - spec/file_spec.rb
87
+ - spec/string_ext_spec.rb
78
88
  - spec/array_ext_spec.rb
79
- - spec/base.rb
80
- - spec/box_spec.rb
81
89
  - spec/commands_spec.rb
82
90
  - spec/config_spec.rb
83
- - spec/dir_spec.rb
84
- - spec/entry_spec.rb
85
- - spec/file_spec.rb
86
- - spec/find_by_spec.rb
87
91
  - spec/fixnum_ext_spec.rb
88
- - spec/local_spec.rb
89
- - spec/process_spec.rb
90
- - spec/remote_spec.rb
91
92
  - spec/search_results_spec.rb
93
+ - spec/process_spec.rb
92
94
  - spec/shell_spec.rb
93
- - spec/ssh_tunnel_spec.rb
94
- - spec/string_ext_spec.rb
95
+ - spec/dir_spec.rb
96
+ - spec/entry_spec.rb
97
+ - spec/find_by_spec.rb
98
+ - spec/box_spec.rb
99
+ - spec/process_set_spec.rb
95
100
  has_rdoc: true
96
101
  homepage: http://rush.heroku.com/
97
102
  post_install_message:
@@ -114,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
119
  requirements: []
115
120
 
116
121
  rubyforge_project: ruby-shell
117
- rubygems_version: 1.0.1
122
+ rubygems_version: 1.2.0
118
123
  signing_key:
119
124
  specification_version: 2
120
125
  summary: A Ruby replacement for bash+ssh.