rush 0.2 → 0.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.
data/Rakefile CHANGED
@@ -31,7 +31,7 @@ require 'rake/rdoctask'
31
31
  require 'fileutils'
32
32
  include FileUtils
33
33
 
34
- version = "0.2"
34
+ version = "0.3"
35
35
  name = "rush"
36
36
 
37
37
  spec = Gem::Specification.new do |s|
data/bin/rush CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require File.dirname(__FILE__) + '/../lib/rush'
4
- require 'shell'
4
+ require File.dirname(__FILE__) + '/../lib/rush/shell'
5
+
5
6
  Rush::Shell.new.run
6
7
 
data/bin/rushd CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require File.dirname(__FILE__) + '/../lib/rush'
4
- require 'server'
4
+ require File.dirname(__FILE__) + '/../lib/rush/server'
5
+
5
6
  RushServer.new.run
6
7
 
@@ -3,22 +3,23 @@ require 'rubygems'
3
3
  module Rush; end
4
4
  module Rush::Connection; end
5
5
 
6
- $LOAD_PATH.unshift(File.dirname(__FILE__) + '/rush')
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
7
 
8
- require 'exceptions'
9
- require 'config'
10
- require 'commands'
11
- require 'entry'
12
- require 'file'
13
- require 'dir'
14
- require 'search_results'
15
- require 'head_tail'
16
- require 'find_by'
17
- require 'string_ext'
18
- require 'fixnum_ext'
19
- require 'array_ext'
20
- require 'process'
21
- require 'local'
22
- require 'remote'
23
- require 'ssh_tunnel'
24
- require 'box'
8
+ require 'rush/exceptions'
9
+ require 'rush/config'
10
+ require 'rush/commands'
11
+ require 'rush/access'
12
+ require 'rush/entry'
13
+ require 'rush/file'
14
+ require 'rush/dir'
15
+ require 'rush/search_results'
16
+ require 'rush/head_tail'
17
+ require 'rush/find_by'
18
+ require 'rush/string_ext'
19
+ require 'rush/fixnum_ext'
20
+ require 'rush/array_ext'
21
+ require 'rush/process'
22
+ require 'rush/local'
23
+ require 'rush/remote'
24
+ require 'rush/ssh_tunnel'
25
+ require 'rush/box'
@@ -0,0 +1,130 @@
1
+ # A class to hold permissions (read, write, execute) for files and dirs.
2
+ # See Rush::Entry#access= for information on the public-facing interface.
3
+ class Rush::Access
4
+ attr_accessor :user_can_read, :user_can_write, :user_can_execute
5
+ attr_accessor :group_can_read, :group_can_write, :group_can_execute
6
+ attr_accessor :other_can_read, :other_can_write, :other_can_execute
7
+
8
+ def self.roles
9
+ %w(user group other)
10
+ end
11
+
12
+ def self.permissions
13
+ %w(read write execute)
14
+ end
15
+
16
+ def parse(options)
17
+ options.each do |key, value|
18
+ next unless m = key.to_s.match(/(.*)_can$/)
19
+ key = m[1].to_sym
20
+ roles = extract_list('role', key, self.class.roles)
21
+ perms = extract_list('permission', value, self.class.permissions)
22
+ set_matrix(perms, roles)
23
+ end
24
+ self
25
+ end
26
+
27
+ def self.parse(options)
28
+ new.parse(options)
29
+ end
30
+
31
+ def apply(full_path)
32
+ FileUtils.chmod(octal_permissions, full_path)
33
+ rescue Errno::ENOENT
34
+ raise Rush::DoesNotExist, full_path
35
+ end
36
+
37
+ def to_hash
38
+ hash = {}
39
+ self.class.roles.each do |role|
40
+ self.class.permissions.each do |perm|
41
+ key = "#{role}_can_#{perm}".to_sym
42
+ hash[key] = send(key) ? 1 : 0
43
+ end
44
+ end
45
+ hash
46
+ end
47
+
48
+ def display_hash
49
+ hash = {}
50
+ to_hash.each do |key, value|
51
+ hash[key] = true if value == 1
52
+ end
53
+ hash
54
+ end
55
+
56
+ def from_hash(hash)
57
+ self.class.roles.each do |role|
58
+ self.class.permissions.each do |perm|
59
+ key = "#{role}_can_#{perm}"
60
+ send("#{key}=".to_sym, hash[key.to_sym].to_i == 1 ? true : false)
61
+ end
62
+ end
63
+ self
64
+ end
65
+
66
+ def self.from_hash(hash)
67
+ new.from_hash(hash)
68
+ end
69
+
70
+ def octal_permissions
71
+ perms = [ 0, 0, 0 ]
72
+ perms[0] += 4 if user_can_read
73
+ perms[0] += 2 if user_can_write
74
+ perms[0] += 1 if user_can_execute
75
+
76
+ perms[1] += 4 if group_can_read
77
+ perms[1] += 2 if group_can_write
78
+ perms[1] += 1 if group_can_execute
79
+
80
+ perms[2] += 4 if other_can_read
81
+ perms[2] += 2 if other_can_write
82
+ perms[2] += 1 if other_can_execute
83
+
84
+ eval("0" + perms.join)
85
+ end
86
+
87
+ def from_octal(mode)
88
+ perms = octal_integer_array(mode)
89
+
90
+ self.user_can_read = (perms[0] & 4) > 0 ? true : false
91
+ self.user_can_write = (perms[0] & 2) > 0 ? true : false
92
+ self.user_can_execute = (perms[0] & 1) > 0 ? true : false
93
+
94
+ self.group_can_read = (perms[1] & 4) > 0 ? true : false
95
+ self.group_can_write = (perms[1] & 2) > 0 ? true : false
96
+ self.group_can_execute = (perms[1] & 1) > 0 ? true : false
97
+
98
+ self.other_can_read = (perms[2] & 4) > 0 ? true : false
99
+ self.other_can_write = (perms[2] & 2) > 0 ? true : false
100
+ self.other_can_execute = (perms[2] & 1) > 0 ? true : false
101
+
102
+ self
103
+ end
104
+
105
+ def octal_integer_array(mode)
106
+ mode %= 01000 # filter out everything but the bottom three digits
107
+ mode = sprintf("%o", mode) # convert to string
108
+ mode.split("").map { |p| p.to_i } # and finally, array of integers
109
+ end
110
+
111
+ def set_matrix(perms, roles)
112
+ perms.each do |perm|
113
+ roles.each do |role|
114
+ meth = "#{role}_can_#{perm}=".to_sym
115
+ send(meth, true)
116
+ end
117
+ end
118
+ end
119
+
120
+ def extract_list(type, value, choices)
121
+ list = parts_from(value)
122
+ list.each do |value|
123
+ raise(Rush::BadAccessSpecifier, "Unrecognized #{type}: #{value}") unless choices.include? value
124
+ end
125
+ end
126
+
127
+ def parts_from(value)
128
+ value.to_s.split('_').reject { |r| r == 'and' }
129
+ end
130
+ end
@@ -49,10 +49,27 @@ class Rush::Box
49
49
  end
50
50
  end
51
51
 
52
- # Execute a command in the standard unix shell. Until the day when it's no
53
- # longer needed...
54
- def bash(command)
55
- connection.bash(command)
52
+ # Execute a command in the standard unix shell. Options:
53
+ #
54
+ # :user => unix username to become via sudo
55
+ # :env => hash of environment variables
56
+ #
57
+ # Example:
58
+ #
59
+ # box.bash '/etc/init.d/mysql restart', :user => 'root'
60
+ # box.bash 'rake db:migrate', :user => 'www', :env => { :RAILS_ENV => 'production' }
61
+ #
62
+ def bash(command, options={})
63
+ connection.bash(command_with_environment(command, options[:env]), options[:user])
64
+ end
65
+
66
+ def command_with_environment(command, env) # :nodoc:
67
+ return command unless env
68
+
69
+ vars = env.map do |key, value|
70
+ "export #{key}='#{value}'"
71
+ end
72
+ vars.push(command).join("\n")
56
73
  end
57
74
 
58
75
  # Returns true if the box is responding to commands.
@@ -118,9 +118,9 @@ class Rush::Dir < Rush::Entry
118
118
  end
119
119
  end
120
120
 
121
- # Run a bash command starting in this directory.
122
- def bash(command)
123
- box.bash "cd #{full_path} && #{command}"
121
+ # Run a bash command starting in this directory. Options are the same as Rush::Box#bash.
122
+ def bash(command, options={})
123
+ box.bash "cd #{full_path} && #{command}", options
124
124
  end
125
125
 
126
126
  # Destroy all of the contents of the directory, leaving it fresh and clean.
@@ -129,6 +129,38 @@ class Rush::Entry
129
129
  name.slice(0, 1) == '.'
130
130
  end
131
131
 
132
+ # Set the access permissions for the entry.
133
+ #
134
+ # Permissions are set by role and permissions combinations which can be specified individually
135
+ # or grouped together. :user_can => :read, :user_can => :write is the same
136
+ # as :user_can => :read_write.
137
+ #
138
+ # You can also insert 'and' if you find it reads better, like :user_and_group_can => :read_and_write.
139
+ #
140
+ # Any permission excluded is set to deny access. The access call does not set partial
141
+ # permissions which combine with the existing state of the entry, like "chmod o+r" would.
142
+ #
143
+ # Examples:
144
+ #
145
+ # file.access = { :user_can => :read_write, :group_other_can => :read }
146
+ # dir.access = { :user => 'adam', :group => 'users', :read_write_execute => :user_group }
147
+ #
148
+ def access=(options)
149
+ connection.set_access(full_path, Rush::Access.parse(options))
150
+ end
151
+
152
+ # Returns a hash with up to nine values, combining user/group/other with read/write/execute.
153
+ # The key is omitted if the value is false.
154
+ #
155
+ # Examples:
156
+ #
157
+ # entry.access # -> { :user_can_read => true, :user_can_write => true, :group_can_read => true }
158
+ # entry.access[:other_can_read] # -> true or nil
159
+ #
160
+ def access
161
+ Rush::Access.new.from_octal(stat[:mode]).display_hash
162
+ end
163
+
132
164
  # Destroy the entry. If it is a dir, everything inside it will also be destroyed.
133
165
  def destroy
134
166
  connection.destroy(full_path)
@@ -23,4 +23,7 @@ module Rush
23
23
 
24
24
  # You cannot move or copy entries to a path that is not a dir (should end with trailing slash).
25
25
  class NotADir < Exception; end
26
+
27
+ # A user or permission value specified to set access was not valid.
28
+ class BadAccessSpecifier < Exception; end
26
29
  end
@@ -12,6 +12,8 @@ module Rush::FindBy
12
12
  find_by(m[1], args.first)
13
13
  elsif m = meth.to_s.match(/^find_all_by_([a-z_]+)$/)
14
14
  find_all_by(m[1], args.first)
15
+ else
16
+ super
15
17
  end
16
18
  end
17
19
 
@@ -114,11 +114,16 @@ class Rush::Connection::Local
114
114
  :ctime => s.ctime,
115
115
  :atime => s.atime,
116
116
  :mtime => s.mtime,
117
+ :mode => s.mode
117
118
  }
118
119
  rescue Errno::ENOENT
119
120
  raise Rush::DoesNotExist, full_path
120
121
  end
121
122
 
123
+ def set_access(full_path, access)
124
+ access.apply(full_path)
125
+ end
126
+
122
127
  # Fetch the size of a dir, since a standard file stat does not include the
123
128
  # size of the contents.
124
129
  def size(full_path)
@@ -253,11 +258,17 @@ class Rush::Connection::Local
253
258
  ::Process.kill('KILL', pid) rescue nil
254
259
  end
255
260
 
256
- def bash(command)
261
+ def bash(command, user=nil)
257
262
  require 'session'
258
263
 
259
264
  sh = Session::Bash.new
260
- out, err = sh.execute command
265
+
266
+ if user and user != ""
267
+ out, err = sh.execute "sudo -u #{user} bash", :stdin => command
268
+ else
269
+ out, err = sh.execute command
270
+ end
271
+
261
272
  retval = sh.status
262
273
  sh.close!
263
274
 
@@ -288,11 +299,12 @@ class Rush::Connection::Local
288
299
  when 'write_archive' then write_archive(params[:payload], params[:dir])
289
300
  when 'index' then index(params[:base_path], params[:glob]).join("\n") + "\n"
290
301
  when 'stat' then YAML.dump(stat(params[:full_path]))
302
+ when 'set_access' then set_access(params[:full_path], Rush::Access.from_hash(params))
291
303
  when 'size' then size(params[:full_path])
292
304
  when 'processes' then YAML.dump(processes)
293
305
  when 'process_alive' then process_alive(params[:pid]) ? '1' : '0'
294
306
  when 'kill_process' then kill_process(params[:pid].to_i)
295
- when 'bash' then bash(params[:payload])
307
+ when 'bash' then bash(params[:payload], params[:user])
296
308
  else
297
309
  raise UnknownAction
298
310
  end
@@ -58,6 +58,10 @@ class Rush::Connection::Remote
58
58
  YAML.load(transmit(:action => 'stat', :full_path => full_path))
59
59
  end
60
60
 
61
+ def set_access(full_path, access)
62
+ transmit access.to_hash.merge(:action => 'set_access', :full_path => full_path)
63
+ end
64
+
61
65
  def size(full_path)
62
66
  transmit(:action => 'size', :full_path => full_path)
63
67
  end
@@ -74,8 +78,8 @@ class Rush::Connection::Remote
74
78
  transmit(:action => 'kill_process', :pid => pid)
75
79
  end
76
80
 
77
- def bash(command)
78
- transmit(:action => 'bash', :payload => command)
81
+ def bash(command, user)
82
+ transmit(:action => 'bash', :payload => command, :user => user)
79
83
  end
80
84
 
81
85
  # Given a hash of parameters (converted by the method call on the connection
@@ -46,9 +46,9 @@ module Rush
46
46
  eval("_ = $last_res", @pure_binding)
47
47
  print_result res
48
48
  rescue Rush::Exception => e
49
- puts "Exception #{e.class} -> #{e}"
49
+ puts "Exception #{e.class} -> #{e.message}"
50
50
  rescue ::Exception => e
51
- puts "Exception #{e.class} -> #{e}"
51
+ puts "Exception #{e.class} -> #{e.message}"
52
52
  e.backtrace.each do |t|
53
53
  puts " #{::File.expand_path(t)}"
54
54
  end
@@ -119,7 +119,7 @@ module Rush
119
119
  if full_path and box
120
120
  dir = Rush::Dir.new(full_path, box)
121
121
  return dir.entries.select do |e|
122
- e.name.match(/^#{partial_path}/)
122
+ e.name.match(/^#{Regexp.escape(partial_path)}/)
123
123
  end.map do |e|
124
124
  (pre || '') + original_var + '[' + quote + fixed_path + e.name + (e.dir? ? "/" : "")
125
125
  end
@@ -0,0 +1,134 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Rush::Access do
4
+ before do
5
+ @access = Rush::Access.new
6
+ end
7
+
8
+ it "has roles: user, group, other" do
9
+ @access.class.roles == %w(user group other)
10
+ end
11
+
12
+ it "has permissions: read, write, execute" do
13
+ @access.class.permissions == %w(read write execute)
14
+ end
15
+
16
+ it "gets parts from a one-part symbol like :user" do
17
+ @access.parts_from(:user).should == %w(user)
18
+ end
19
+
20
+ it "gets parts from a two-part symbol like :read_write" do
21
+ @access.parts_from(:read_write).should == %w(read write)
22
+ end
23
+
24
+ it "allows use of 'and' in multipart symbols, like :user_and_group" do
25
+ @access.parts_from(:user_and_group).should == %w(user group)
26
+ end
27
+
28
+ it "extract_list verifies that all the parts among the valid choices" do
29
+ @access.should_receive(:parts_from).with(:red_green).and_return(%w(red green))
30
+ @access.extract_list('type', :red_green, %w(red blue green)).should == %w(red green)
31
+ end
32
+
33
+ it "extract_list raises a BadAccessSpecifier when there is part not in the list of choices" do
34
+ lambda do
35
+ @access.extract_list('role', :user_bork, %w(user group))
36
+ end.should raise_error(Rush::BadAccessSpecifier, "Unrecognized role: bork")
37
+ end
38
+
39
+ it "sets one value in the matrix of permissions and roles" do
40
+ @access.set_matrix(%w(read), %w(user))
41
+ @access.user_can_read.should == true
42
+ end
43
+
44
+ it "sets two values in the matrix of permissions and roles" do
45
+ @access.set_matrix(%w(read), %w(user group))
46
+ @access.user_can_read.should == true
47
+ @access.group_can_read.should == true
48
+ end
49
+
50
+ it "sets four values in the matrix of permissions and roles" do
51
+ @access.set_matrix(%w(read write), %w(user group))
52
+ @access.user_can_read.should == true
53
+ @access.group_can_read.should == true
54
+ @access.user_can_write.should == true
55
+ @access.group_can_write.should == true
56
+ end
57
+
58
+ it "parse options hash" do
59
+ @access.parse(:user_can => :read)
60
+ @access.user_can_read.should == true
61
+ end
62
+
63
+ it "generates octal permissions from its member vars" do
64
+ @access.user_can_read = true
65
+ @access.octal_permissions.should == 0400
66
+ end
67
+
68
+ it "generates octal permissions from its member vars" do
69
+ @access.user_can_read = true
70
+ @access.user_can_write = true
71
+ @access.user_can_execute = true
72
+ @access.group_can_read = true
73
+ @access.group_can_execute = true
74
+ @access.octal_permissions.should == 0750
75
+ end
76
+
77
+ it "applies its settings to a file" do
78
+ file = "/tmp/rush_spec_#{Process.pid}"
79
+ begin
80
+ system "rm -rf #{file}; touch #{file}; chmod 770 #{file}"
81
+ @access.user_can_read = true
82
+ @access.apply(file)
83
+ `ls -l #{file}`.should match(/^-r--------/)
84
+ ensure
85
+ system "rm -rf #{file}; touch #{file}"
86
+ end
87
+ end
88
+
89
+ it "serializes itself to a hash" do
90
+ @access.user_can_read = true
91
+ @access.to_hash.should == {
92
+ :user_can_read => 1, :user_can_write => 0, :user_can_execute => 0,
93
+ :group_can_read => 0, :group_can_write => 0, :group_can_execute => 0,
94
+ :other_can_read => 0, :other_can_write => 0, :other_can_execute => 0,
95
+ }
96
+ end
97
+
98
+ it "unserializes from a hash" do
99
+ @access.from_hash(:user_can_read => '1')
100
+ @access.user_can_read.should == true
101
+ end
102
+
103
+ it "initializes from a serialized hash" do
104
+ @access.class.should_receive(:new).and_return(@access)
105
+ @access.class.from_hash(:user_can_read => '1').should == @access
106
+ @access.user_can_read.should == true
107
+ end
108
+
109
+ it "initializes from a parsed options hash" do
110
+ @access.class.should_receive(:new).and_return(@access)
111
+ @access.class.parse(:user_and_group_can => :read).should == @access
112
+ @access.user_can_read.should == true
113
+ end
114
+
115
+ it "converts and octal integer into an array of integers" do
116
+ @access.octal_integer_array(0740).should == [ 7, 4, 0 ]
117
+ end
118
+
119
+ it "filters out anything above the top three digits (File.stat returns some extra data there)" do
120
+ @access.octal_integer_array(0100644).should == [ 6, 4, 4 ]
121
+ end
122
+
123
+ it "taskes permissions from an octal representation" do
124
+ @access.from_octal(0644)
125
+ @access.user_can_read.should == true
126
+ @access.user_can_write.should == true
127
+ @access.user_can_execute.should == false
128
+ end
129
+
130
+ it "computes a display hash by dropping false keys and converting the 1s to trues" do
131
+ @access.should_receive(:to_hash).and_return(:red => 1, :green => 0, :blue => 1)
132
+ @access.display_hash.should == { :red => true, :blue => true }
133
+ end
134
+ end
@@ -22,10 +22,25 @@ describe Rush::Box do
22
22
  end
23
23
 
24
24
  it "executes bash commands" do
25
- @box.connection.should_receive(:bash).with('cmd').and_return('output')
25
+ @box.connection.should_receive(:bash).with('cmd', nil).and_return('output')
26
26
  @box.bash('cmd').should == 'output'
27
27
  end
28
28
 
29
+ it "executes bash commands with an optional user" do
30
+ @box.connection.should_receive(:bash).with('cmd', 'user')
31
+ @box.bash('cmd', :user => 'user')
32
+ end
33
+
34
+ it "builds a script of environment variables to prefix the bash command" do
35
+ @box.command_with_environment('cmd', { :a => 'b' }).should == "export a='b'\ncmd"
36
+ end
37
+
38
+ it "sets the environment variables from the provided hash" do
39
+ @box.connection.stub!(:bash)
40
+ @box.should_receive(:command_with_environment).with('cmd', { 1 => 2 })
41
+ @box.bash('cmd', :env => { 1 => 2 })
42
+ end
43
+
29
44
  it "checks the connection to determine if it is alive" do
30
45
  @box.connection.should_receive(:alive?).and_return(true)
31
46
  @box.should be_alive
@@ -150,4 +150,10 @@ describe Rush::Dir do
150
150
  system "echo test > #{@dir.full_path}/file"
151
151
  @dir.bash("cat file").should == "test\n"
152
152
  end
153
+
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')
157
+ end
158
+
153
159
  end
@@ -115,4 +115,15 @@ describe Rush::Entry do
115
115
  copy.mimic(@entry)
116
116
  copy.path.should == @entry.path
117
117
  end
118
+
119
+ it "can update the read access permission" do
120
+ system "chmod 666 #{@filename}"
121
+ @entry.access = { :user_can => :read }
122
+ `ls -l #{@filename}`.should match(/^-r--------/)
123
+ end
124
+
125
+ it "reads the file permissions in the access hash" do
126
+ system "chmod 640 #{@filename}"
127
+ @entry.access.should == { :user_can_read => true, :user_can_write => true, :group_can_read => true }
128
+ end
118
129
  end
@@ -7,8 +7,7 @@ describe Rush::FindBy do
7
7
 
8
8
  def initialize(bar)
9
9
  @bar = bar
10
- end
11
- end
10
+ end end
12
11
 
13
12
  @one = Foo.new('one')
14
13
  @two = Foo.new('two')
@@ -52,4 +51,8 @@ describe Rush::FindBy do
52
51
  it "find_by_ with field not recognized by objects raises no errors" do
53
52
  @list.find_by_nothing('x')
54
53
  end
54
+
55
+ it "raises NoMethodError for things other than find_by" do
56
+ lambda { @list.does_not_exist }.should raise_error(NoMethodError)
57
+ end
55
58
  end
@@ -67,6 +67,14 @@ describe Rush::Connection::Local do
67
67
  @con.receive(:action => 'stat', :full_path => 'full_path').should == YAML.dump(1 => 2)
68
68
  end
69
69
 
70
+ it "receive -> set_access(full_path, user, group, permissions)" do
71
+ access = mock("access")
72
+ Rush::Access.should_receive(:from_hash).with(:action => 'set_access', :full_path => 'full_path', :user => 'joe').and_return(access)
73
+
74
+ @con.should_receive(:set_access).with('full_path', access)
75
+ @con.receive(:action => 'set_access', :full_path => 'full_path', :user => 'joe')
76
+ end
77
+
70
78
  it "receive -> size(full_path)" do
71
79
  @con.should_receive(:size).with('full_path').and_return("1024")
72
80
  @con.receive(:action => 'size', :full_path => 'full_path').should == "1024"
@@ -88,8 +96,8 @@ describe Rush::Connection::Local do
88
96
  end
89
97
 
90
98
  it "receive -> bash" do
91
- @con.should_receive(:bash).with('cmd').and_return('output')
92
- @con.receive(:action => 'bash', :payload => 'cmd').should == 'output'
99
+ @con.should_receive(:bash).with('cmd', 'user').and_return('output')
100
+ @con.receive(:action => 'bash', :payload => 'cmd', :user => 'user').should == 'output'
93
101
  end
94
102
 
95
103
  it "receive -> unknown action exception" do
@@ -132,7 +140,7 @@ describe Rush::Connection::Local do
132
140
  system "cd #{@sandbox_dir}; touch .killme"
133
141
  @con.purge(@sandbox_dir)
134
142
  File.exists?(@sandbox_dir).should be_true
135
- `cd #{@sandbox_dir}; ls -lA | wc -l`.to_i.should == 0
143
+ `cd #{@sandbox_dir}; ls -lA | grep -v total | wc -l`.to_i.should == 0
136
144
  end
137
145
 
138
146
  it "create_dir creates a directory" do
@@ -196,11 +204,21 @@ describe Rush::Connection::Local do
196
204
  @con.stat(@sandbox_dir).should have_key(:size)
197
205
  end
198
206
 
207
+ it "stat fetches the octal permissions" do
208
+ @con.stat(@sandbox_dir)[:mode].should be_kind_of(Fixnum)
209
+ end
210
+
199
211
  it "stat raises DoesNotExist if the entry does not exist" do
200
212
  fname = "#{@sandbox_dir}/does_not_exist"
201
213
  lambda { @con.stat(fname) }.should raise_error(Rush::DoesNotExist, fname)
202
214
  end
203
215
 
216
+ it "set_access invokes the access object" do
217
+ access = mock("access")
218
+ access.should_receive(:apply).with('/some/path')
219
+ @con.set_access('/some/path', access)
220
+ end
221
+
204
222
  if !RUBY_PLATFORM.match(/darwin/) # doesn't work on OS X 'cause du switches are different
205
223
  it "size gives size of a directory and all its contents recursively" do
206
224
  system "mkdir -p #{@sandbox_dir}/a/b/; echo 1234 > #{@sandbox_dir}/a/b/c"
@@ -253,6 +271,10 @@ EOPS
253
271
  lambda { @con.bash("no_such_bin") }.should raise_error(Rush::BashFailed, /command not found/)
254
272
  end
255
273
 
274
+ it "executes a bash command as another user using sudo" do
275
+ @con.bash("echo test2", ENV['user']).should == "test2\n"
276
+ end
277
+
256
278
  it "ensure_tunnel to match with remote connection" do
257
279
  @con.ensure_tunnel
258
280
  end
@@ -67,6 +67,11 @@ describe Rush::Connection::Local do
67
67
  @con.stat('full_path').should == { 1 => 2 }
68
68
  end
69
69
 
70
+ it "transmits set_access" do
71
+ @con.should_receive(:transmit).with(:action => 'set_access', :full_path => 'full_path', :user => 'joe', :user_read => 1)
72
+ @con.set_access('full_path', :user => 'joe', :user_read => 1)
73
+ end
74
+
70
75
  it "transmits size" do
71
76
  @con.should_receive(:transmit).with(:action => 'size', :full_path => 'full_path').and_return("")
72
77
  @con.size('full_path')
@@ -88,8 +93,8 @@ describe Rush::Connection::Local do
88
93
  end
89
94
 
90
95
  it "transmits bash" do
91
- @con.should_receive(:transmit).with(:action => 'bash', :payload => 'cmd').and_return('output')
92
- @con.bash('cmd').should == 'output'
96
+ @con.should_receive(:transmit).with(:action => 'bash', :payload => 'cmd', :user => 'user').and_return('output')
97
+ @con.bash('cmd', 'user').should == 'output'
93
98
  end
94
99
 
95
100
  it "an http result code of 401 raises NotAuthorized" do
@@ -1,5 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/base'
2
- require 'shell'
2
+ require 'rush/shell'
3
3
 
4
4
  describe Rush::Shell do
5
5
  before 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.2"
4
+ version: "0.3"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Wiggins
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-03-12 00:00:00 -07:00
12
+ date: 2008-03-26 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -53,6 +53,7 @@ files:
53
53
  - bin/rush
54
54
  - bin/rushd
55
55
  - lib/rush
56
+ - lib/rush/access.rb
56
57
  - lib/rush/array_ext.rb
57
58
  - lib/rush/box.rb
58
59
  - lib/rush/commands.rb
@@ -73,6 +74,7 @@ files:
73
74
  - lib/rush/ssh_tunnel.rb
74
75
  - lib/rush/string_ext.rb
75
76
  - lib/rush.rb
77
+ - spec/access_spec.rb
76
78
  - spec/array_ext_spec.rb
77
79
  - spec/base.rb
78
80
  - spec/box_spec.rb