rush2 0.7.0

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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +13 -0
  3. data/Gemfile.lock +86 -0
  4. data/README.rdoc +125 -0
  5. data/Rakefile +57 -0
  6. data/VERSION +1 -0
  7. data/bin/rush +13 -0
  8. data/bin/rushd +7 -0
  9. data/lib/rush.rb +91 -0
  10. data/lib/rush/access.rb +121 -0
  11. data/lib/rush/array_ext.rb +19 -0
  12. data/lib/rush/box.rb +124 -0
  13. data/lib/rush/commands.rb +76 -0
  14. data/lib/rush/config.rb +147 -0
  15. data/lib/rush/dir.rb +166 -0
  16. data/lib/rush/embeddable_shell.rb +26 -0
  17. data/lib/rush/entry.rb +229 -0
  18. data/lib/rush/exceptions.rb +32 -0
  19. data/lib/rush/file.rb +94 -0
  20. data/lib/rush/find_by.rb +39 -0
  21. data/lib/rush/fixnum_ext.rb +18 -0
  22. data/lib/rush/head_tail.rb +11 -0
  23. data/lib/rush/local.rb +377 -0
  24. data/lib/rush/process.rb +59 -0
  25. data/lib/rush/process_set.rb +62 -0
  26. data/lib/rush/remote.rb +33 -0
  27. data/lib/rush/search_results.rb +71 -0
  28. data/lib/rush/shell.rb +111 -0
  29. data/lib/rush/shell/completion.rb +110 -0
  30. data/lib/rush/string_ext.rb +16 -0
  31. data/spec/access_spec.rb +134 -0
  32. data/spec/array_ext_spec.rb +15 -0
  33. data/spec/base.rb +22 -0
  34. data/spec/box_spec.rb +76 -0
  35. data/spec/commands_spec.rb +47 -0
  36. data/spec/config_spec.rb +108 -0
  37. data/spec/dir_spec.rb +163 -0
  38. data/spec/embeddable_shell_spec.rb +17 -0
  39. data/spec/entry_spec.rb +133 -0
  40. data/spec/file_spec.rb +83 -0
  41. data/spec/find_by_spec.rb +58 -0
  42. data/spec/fixnum_ext_spec.rb +19 -0
  43. data/spec/local_spec.rb +365 -0
  44. data/spec/process_set_spec.rb +50 -0
  45. data/spec/process_spec.rb +73 -0
  46. data/spec/remote_spec.rb +140 -0
  47. data/spec/rush_spec.rb +28 -0
  48. data/spec/search_results_spec.rb +44 -0
  49. data/spec/shell_spec.rb +35 -0
  50. data/spec/ssh_tunnel_spec.rb +122 -0
  51. data/spec/string_ext_spec.rb +23 -0
  52. metadata +209 -0
@@ -0,0 +1,15 @@
1
+ require_relative 'base'
2
+
3
+ describe Array do
4
+ it "mixes commands into array" do
5
+ [ 1,2,3 ].entries.should == [ 1, 2, 3 ]
6
+ end
7
+
8
+ it "can call head" do
9
+ [ 1,2,3 ].head(1).should == [ 1 ]
10
+ end
11
+
12
+ it "can call tail" do
13
+ [ 1,2,3 ].tail(1).should == [ 3 ]
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ require 'rspec'
2
+
3
+ require_relative '../lib/rush'
4
+
5
+ def mock_config(&block)
6
+ mock_config_start
7
+ block.call(config)
8
+ mock_config_end
9
+ end
10
+
11
+ def mock_config_sandbox_dir
12
+ "/tmp/fake_config.#{Process.pid}"
13
+ end
14
+
15
+ def mock_config_start
16
+ mock_config_cleanup
17
+ Rush::Config.new(mock_config_sandbox_dir)
18
+ end
19
+
20
+ def mock_config_cleanup
21
+ FileUtils.rm_rf(mock_config_sandbox_dir)
22
+ end
@@ -0,0 +1,76 @@
1
+ require_relative 'base'
2
+
3
+ describe Rush::Box do
4
+ before do
5
+ @sandbox_dir = "/tmp/rush_spec.#{Process.pid}"
6
+ system "rm -rf #{@sandbox_dir}; mkdir -p #{@sandbox_dir}"
7
+
8
+ @box = Rush::Box.new('localhost')
9
+ end
10
+
11
+ after do
12
+ system "rm -rf #{@sandbox_dir}"
13
+ end
14
+
15
+ it "looks up entries with [] syntax" do
16
+ @box['/'].should == Rush::Dir.new('/', @box)
17
+ end
18
+
19
+ it "looks up processes" do
20
+ @box.connection.should_receive(:processes).and_return([ { :pid => 123 } ])
21
+ @box.processes.should == [ Rush::Process.new({ :pid => 123 }, @box) ]
22
+ end
23
+
24
+ it "executes bash commands" do
25
+ @box.connection.should_receive(:bash).with('cmd', nil, false, false).and_return('output')
26
+ @box.bash('cmd').should == 'output'
27
+ end
28
+
29
+ it "executes bash commands with an optional user" do
30
+ @box.connection.should_receive(:bash).with('cmd', 'user', false, false)
31
+ @box.bash('cmd', :user => 'user')
32
+ end
33
+
34
+ it "executes bash commands in the background, returning a Rush::Process" do
35
+ @box.connection.should_receive(:bash).with('cmd', nil, true, false).and_return(123)
36
+ @box.stub(:processes).and_return([ double('ps', :pid => 123) ])
37
+ @box.bash('cmd', :background => true).pid.should == 123
38
+ end
39
+
40
+ it "builds a script of environment variables to prefix the bash command" do
41
+ @box.command_with_environment('cmd', { :a => 'b' }).should == "export a=\"b\"\ncmd"
42
+ end
43
+
44
+ it "escapes quotes on environment variables" do
45
+ @box.command_with_environment('cmd', { :a => 'a"b' }).should == "export a=\"a\\\"b\"\ncmd"
46
+ end
47
+
48
+ it "escapes backticks on environment variables" do
49
+ @box.command_with_environment('cmd', { :a => 'a`b' }).should == "export a=\"a\\\`b\"\ncmd"
50
+ end
51
+
52
+ it "converts environment variables to_s" do
53
+ @box.command_with_environment('cmd', { :a => nil, :b => 123 }).should == "export a=\"\"\nexport b=\"123\"\ncmd"
54
+ end
55
+
56
+ it "sets the environment variables from the provided hash" do
57
+ @box.connection.stub(:bash)
58
+ @box.should_receive(:command_with_environment).with('cmd', { 1 => 2 })
59
+ @box.bash('cmd', :env => { 1 => 2 })
60
+ end
61
+
62
+ it "checks the connection to determine if it is alive" do
63
+ @box.connection.should_receive(:alive?).and_return(true)
64
+ @box.should be_alive
65
+ end
66
+
67
+ it "establish_connection to set up the connection manually" do
68
+ @box.connection.should_receive(:ensure_tunnel)
69
+ @box.establish_connection
70
+ end
71
+
72
+ it "establish_connection can take a hash of options" do
73
+ @box.connection.should_receive(:ensure_tunnel).with(:timeout => :infinite)
74
+ @box.establish_connection(:timeout => :infinite)
75
+ end
76
+ end
@@ -0,0 +1,47 @@
1
+ require_relative 'base'
2
+
3
+ describe Rush::Commands do
4
+ before do
5
+ @sandbox_dir = "/tmp/rush_spec.#{Process.pid}"
6
+ system "rm -rf #{@sandbox_dir}; mkdir -p #{@sandbox_dir}"
7
+
8
+ @filename = "test_file"
9
+ system "echo thing_to_find > #{@sandbox_dir}/#{@filename}"
10
+ system "echo dont_find_me > #{@sandbox_dir}/some_other_file"
11
+
12
+ @dir = Rush::Dir.new(@sandbox_dir)
13
+ @array = @dir.files
14
+ end
15
+
16
+ after do
17
+ system "rm -rf #{@sandbox_dir}"
18
+ end
19
+
20
+ it "searches a list of files" do
21
+ results = @dir.files.search(/thing_to_find/)
22
+ results.should be_kind_of(Rush::SearchResults)
23
+ results.entries.should == [ @dir[@filename] ]
24
+ results.lines.should == [ "thing_to_find" ]
25
+ end
26
+
27
+ it "searches a dir" do
28
+ @dir.search(/thing_to_find/).entries.should == [ @dir[@filename] ]
29
+ end
30
+
31
+ it "searchs a dir's nested files" do
32
+ @dir.create_dir('sub').create_file('file').write('nested')
33
+ @dir['**'].search(/nested/).entries.should == [ @dir['sub/file'] ]
34
+ end
35
+
36
+ it "search and replace contents on all files in the glob" do
37
+ @dir['1'].create.write('xax')
38
+ @dir['2'].create.write('-a-')
39
+ @dir.replace_contents!(/a/, 'b')
40
+ @dir['1'].contents.should == "xbx"
41
+ @dir['2'].contents.should == "-b-"
42
+ end
43
+
44
+ it "counts lines of the contained files" do
45
+ @dir.files.line_count.should == 2
46
+ end
47
+ end
@@ -0,0 +1,108 @@
1
+ require_relative 'base'
2
+
3
+ describe Rush::Config do
4
+ before do
5
+ @sandbox_dir = "/tmp/rush_config_spec.#{Process.pid}"
6
+ system "rm -rf #{@sandbox_dir}"
7
+ @config = Rush::Config.new(@sandbox_dir)
8
+ end
9
+
10
+ after do
11
+ system "rm -rf #{@sandbox_dir}"
12
+ end
13
+
14
+ it "creates the dir" do
15
+ expect(File.directory?(@sandbox_dir)).to eq(true)
16
+ end
17
+
18
+ it "can access the history file" do
19
+ expect(@config.history_file).to be_kind_of(Rush::File)
20
+ end
21
+
22
+ it "saves the shell command history" do
23
+ @config.save_history(%w(1 2 3))
24
+ expect(@config.history_file.contents).to eq("1\n2\n3\n")
25
+ end
26
+
27
+ it "loads the shell command history" do
28
+ @config.save_history(%w(1 2 3))
29
+ expect(@config.load_history).to eq(%w(1 2 3))
30
+ end
31
+
32
+ it "loads a blank history if no history file" do
33
+ expect(@config.load_history).to eq([])
34
+ end
35
+
36
+ it "loads the env file" do
37
+ @config.env_file.write('abc')
38
+ expect(@config.load_env).to eq('abc')
39
+ end
40
+
41
+ it "loads nothing if env file does not exist" do
42
+ expect(@config.load_env).to eq('')
43
+ end
44
+
45
+ it "loads the commands file" do
46
+ @config.commands_file.write('abc')
47
+ expect(@config.load_commands).to eq('abc')
48
+ end
49
+
50
+ it "loads nothing if commands file does not exist" do
51
+ expect(@config.load_commands).to eq('')
52
+ end
53
+
54
+ it "loads usernames and password for rushd" do
55
+ system "echo 1:2 > #{@sandbox_dir}/passwords"
56
+ system "echo a:b >> #{@sandbox_dir}/passwords"
57
+ expect(@config.passwords).to eq({ '1' => '2', 'a' => 'b' })
58
+ end
59
+
60
+ it "loads blank hash if no passwords file" do
61
+ expect(@config.passwords).to eq({})
62
+ end
63
+
64
+ it "loads credentials for client connecting to server" do
65
+ system "echo user:pass > #{@sandbox_dir}/credentials"
66
+ expect(@config.credentials_user).to eq 'user'
67
+ expect(@config.credentials_password).to eq 'pass'
68
+ end
69
+
70
+ it "loads list of ssh tunnels" do
71
+ system "echo host.example.com:123 > #{@sandbox_dir}/tunnels"
72
+ expect(@config.tunnels).to eq({ 'host.example.com' => 123 })
73
+ end
74
+
75
+ it "returns an empty hash if tunnels file is blank" do
76
+ expect(@config.tunnels).to eq({})
77
+ end
78
+
79
+ it "saves a list of ssh tunnels" do
80
+ @config.save_tunnels({ 'my.example.com' => 4000 })
81
+ expect(@config.tunnels_file.contents).to eq "my.example.com:4000\n"
82
+ end
83
+
84
+ it "ensure_credentials_exist doesn't do anything if credentials already exist" do
85
+ @config.credentials_file.write "dummy"
86
+ expect(@config).to receive(:generate_credentials).exactly(0).times
87
+ @config.ensure_credentials_exist
88
+ end
89
+
90
+ it "ensure_credentials_exist generates credentials file if they don't exist" do
91
+ expect(@config).to receive(:generate_credentials)
92
+ @config.ensure_credentials_exist
93
+ end
94
+
95
+ it "secret_characters returns valid characters for username or password" do
96
+ expect(@config.secret_characters).to be_kind_of(Array)
97
+ end
98
+
99
+ it "generate_secret products a random string for use in username and password" do
100
+ expect(@config).to receive(:secret_characters).and_return(%w(a))
101
+ expect(@config.generate_secret(2, 2)).to eq "aa"
102
+ end
103
+
104
+ it "generate_credentials saves credentials" do
105
+ @config.generate_credentials
106
+ expect(@config.credentials_file.contents).to match(/^.+:.+$/)
107
+ end
108
+ end
@@ -0,0 +1,163 @@
1
+ require_relative 'base'
2
+
3
+ describe Rush::Dir do
4
+ before do
5
+ @sandbox_dir = "/tmp/rush_spec.#{Process.pid}"
6
+ system "rm -rf #{@sandbox_dir}; mkdir -p #{@sandbox_dir}"
7
+
8
+ @dirname = "#{@sandbox_dir}/test_dir/"
9
+ system "mkdir -p #{@dirname}"
10
+
11
+ @dir = Rush::Dir.new(@dirname)
12
+ end
13
+
14
+ after do
15
+ system "rm -rf #{@sandbox_dir}"
16
+ end
17
+
18
+ it "is a child of Rush::Entry" do
19
+ expect(@dir).to be_kind_of(Rush::Entry)
20
+ end
21
+
22
+ it "can create itself, returning itself" do
23
+ system "rm -rf #{@sandbox_dir}"
24
+ expect(@dir.create).to eq @dir
25
+ expect(File.directory?(@dir.full_path)).to eq(true)
26
+ end
27
+
28
+ it "can create a new file" do
29
+ newfile = @dir.create_file('one.txt')
30
+ expect(newfile.name).to eq 'one.txt'
31
+ expect(newfile.parent).to eq @dir
32
+ end
33
+
34
+ it "can create a new subdir" do
35
+ newfile = @dir['two/'].create
36
+ expect(newfile.name).to eq 'two'
37
+ expect(newfile.parent).to eq @dir
38
+ end
39
+
40
+ it "find_by_name finds a single entry in the contents" do
41
+ file = @dir.create_file('one.rb')
42
+ expect(@dir.find_by_name('one.rb')).to eq file
43
+ end
44
+
45
+ it "find_by_glob finds a list of entries by wildcard" do
46
+ file1 = @dir.create_file('one.rb')
47
+ file2 = @dir.create_file('two.txt')
48
+ expect(@dir.find_by_glob('*.rb')).to eq([file1])
49
+ end
50
+
51
+ it "lists files" do
52
+ @dir.create_file('a')
53
+ expect(@dir.files).to eq([Rush::File.new("#{@dirname}/a")])
54
+ end
55
+
56
+ it "lists dirs" do
57
+ system "mkdir -p #{@dir.full_path}/b"
58
+ expect(@dir.dirs).to eq([Rush::Dir.new("#{@dirname}/b")])
59
+ end
60
+
61
+ it "lists combined files and dirs" do
62
+ @dir['c'].create
63
+ @dir['d/'].create
64
+ expect(@dir.contents.size).to eq 2
65
+ end
66
+
67
+ it "fetches the entry_tree of all contents recursively" do
68
+ @dir['a/'].create['b/'].create['c'].create
69
+ expect(@dir.entries_tree).to eq @dir.make_entries(%w(a/ a/b/ a/b/c))
70
+ end
71
+
72
+ it "maps [] to find_by_name" do
73
+ expect(@dir).to receive(:find_by_name).once
74
+ @dir['one']
75
+ end
76
+
77
+ it "maps [] with a wildcard character to find_by_glob" do
78
+ expect(@dir).to receive(:find_by_glob).once
79
+ @dir['*']
80
+ end
81
+
82
+ it "can use symbols or strings for [] access" do
83
+ expect(@dir).to receive(:find_by_name).once.with('subdir')
84
+ @dir[:subdir]
85
+ end
86
+
87
+ it "[] can return a file that has yet to be created" do
88
+ expect(@dir['not_yet']).to be_kind_of Rush::File
89
+ end
90
+
91
+ it "makes a list of entries from an array of filenames" do
92
+ @dir['a'].create
93
+ @dir['b/c/'].create
94
+ expect(@dir.make_entries(%w(a b/c))).to eq([ @dir['a'], @dir['b/c'] ])
95
+ end
96
+
97
+ it "lists flattened files from all nested subdirectories" do
98
+ @dir['1'].create
99
+ @dir['2/3/'].create['4'].create
100
+ @dir['a/b/c/'].create['d'].create
101
+ expect(@dir.files_flattened).to eq @dir.make_entries(%w(1 2/3/4 a/b/c/d))
102
+ end
103
+
104
+ it "lists flattened dirs from all nested subdirectories" do
105
+ @dir.create_dir('1/2')
106
+ expect(@dir.dirs_flattened).to eq @dir.make_entries(%w(1/ 1/2/))
107
+ end
108
+
109
+ it "** as a shortcut to flattened_files" do
110
+ expect(@dir['**']).to eq @dir.files_flattened
111
+ end
112
+
113
+ it "**/ as a shortcut to flattened_files + regular globbing" do
114
+ @dir.create_file('1.rb')
115
+ @dir.create_file('ignore.txt')
116
+ @dir.create_dir('2').create_file('3.rb')
117
+ @dir.create_dir('a/b').create_file('c.rb')
118
+ expect(@dir['**/*.rb']).to eq @dir.make_entries(%w(1.rb 2/3.rb a/b/c.rb))
119
+ end
120
+
121
+ it "lists nonhidden files" do
122
+ @dir.create_file('show')
123
+ @dir.create_file('.dont_show')
124
+ expect(@dir.nonhidden_files).to eq @dir.make_entries(%(show))
125
+ end
126
+
127
+ it "lists nonhidden dirs" do
128
+ @dir.create_dir('show')
129
+ @dir.create_dir('.dont_show')
130
+ expect(@dir.nonhidden_dirs).to eq @dir.make_entries(%(show/))
131
+ end
132
+
133
+ if !RUBY_PLATFORM.match(/darwin/) # doesn't work on OS X 'cause du switches are different
134
+ it "knows its size in bytes, which includes its contents recursively" do
135
+ @dir.create_file('a').write('1234')
136
+ expect(@dir.size).to eq(4096 + 4)
137
+ end
138
+ end
139
+
140
+ it "can destroy itself when empty" do
141
+ @dir.destroy
142
+ end
143
+
144
+ it "can destroy itself when not empty" do
145
+ @dir.create_dir('a').create_file('b').write('c')
146
+ @dir.destroy
147
+ end
148
+
149
+ it "can run a bash command within itself" do
150
+ system "echo test > #{@dir.full_path}/file"
151
+ expect(@dir.bash("cat file")).to eq "test\n"
152
+ end
153
+
154
+ it "can run bash within directories with spaces" do
155
+ @dir.create_dir('with space').create_file('file').write('test')
156
+ expect(@dir["with space/"].bash("cat file")).to eq "test"
157
+ end
158
+
159
+ it "passes bash options (e.g., :user) through to the box bash command" do
160
+ expect(@dir).to receive(:bash).with('cmd', :opt1 => 1, :opt2 => 2)
161
+ @dir.bash('cmd', :opt1 => 1, :opt2 => 2)
162
+ end
163
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'base'
2
+
3
+ describe Rush::EmbeddableShell do
4
+ before do
5
+ @shell = Rush::EmbeddableShell.new
6
+ end
7
+
8
+ it "should execute unknown methods against a Rush::Shell instance" do
9
+ @shell.root.class.should == Rush::Dir
10
+ end
11
+
12
+ it "should executes a block as if it were inside the shell" do
13
+ @shell.execute_in_shell {
14
+ root.class.should == Rush::Dir
15
+ }
16
+ end
17
+ end