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 +1 -1
- data/bin/rush +2 -1
- data/bin/rushd +2 -1
- data/lib/rush.rb +19 -18
- data/lib/rush/access.rb +130 -0
- data/lib/rush/box.rb +21 -4
- data/lib/rush/dir.rb +3 -3
- data/lib/rush/entry.rb +32 -0
- data/lib/rush/exceptions.rb +3 -0
- data/lib/rush/find_by.rb +2 -0
- data/lib/rush/local.rb +15 -3
- data/lib/rush/remote.rb +6 -2
- data/lib/rush/shell.rb +3 -3
- data/spec/access_spec.rb +134 -0
- data/spec/box_spec.rb +16 -1
- data/spec/dir_spec.rb +6 -0
- data/spec/entry_spec.rb +11 -0
- data/spec/find_by_spec.rb +5 -2
- data/spec/local_spec.rb +25 -3
- data/spec/remote_spec.rb +7 -2
- data/spec/shell_spec.rb +1 -1
- metadata +4 -2
data/Rakefile
CHANGED
data/bin/rush
CHANGED
data/bin/rushd
CHANGED
data/lib/rush.rb
CHANGED
@@ -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__)
|
6
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
7
|
|
8
|
-
require 'exceptions'
|
9
|
-
require 'config'
|
10
|
-
require 'commands'
|
11
|
-
require '
|
12
|
-
require '
|
13
|
-
require '
|
14
|
-
require '
|
15
|
-
require '
|
16
|
-
require '
|
17
|
-
require '
|
18
|
-
require '
|
19
|
-
require '
|
20
|
-
require '
|
21
|
-
require '
|
22
|
-
require '
|
23
|
-
require '
|
24
|
-
require '
|
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'
|
data/lib/rush/access.rb
ADDED
@@ -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
|
data/lib/rush/box.rb
CHANGED
@@ -49,10 +49,27 @@ class Rush::Box
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
# Execute a command in the standard unix shell.
|
53
|
-
#
|
54
|
-
|
55
|
-
|
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.
|
data/lib/rush/dir.rb
CHANGED
@@ -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.
|
data/lib/rush/entry.rb
CHANGED
@@ -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)
|
data/lib/rush/exceptions.rb
CHANGED
@@ -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
|
data/lib/rush/find_by.rb
CHANGED
data/lib/rush/local.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/rush/remote.rb
CHANGED
@@ -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
|
data/lib/rush/shell.rb
CHANGED
@@ -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
|
data/spec/access_spec.rb
ADDED
@@ -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
|
data/spec/box_spec.rb
CHANGED
@@ -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
|
data/spec/dir_spec.rb
CHANGED
@@ -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
|
data/spec/entry_spec.rb
CHANGED
@@ -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
|
data/spec/find_by_spec.rb
CHANGED
@@ -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
|
data/spec/local_spec.rb
CHANGED
@@ -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
|
data/spec/remote_spec.rb
CHANGED
@@ -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
|
data/spec/shell_spec.rb
CHANGED
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.
|
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
|
+
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
|