rush3 3.0.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 +15 -0
  3. data/Gemfile.lock +93 -0
  4. data/README.rdoc +124 -0
  5. data/Rakefile +58 -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 +16 -0
  12. data/lib/rush/box.rb +130 -0
  13. data/lib/rush/commands.rb +94 -0
  14. data/lib/rush/config.rb +147 -0
  15. data/lib/rush/dir.rb +159 -0
  16. data/lib/rush/embeddable_shell.rb +26 -0
  17. data/lib/rush/entry.rb +238 -0
  18. data/lib/rush/exceptions.rb +32 -0
  19. data/lib/rush/file.rb +100 -0
  20. data/lib/rush/find_by.rb +39 -0
  21. data/lib/rush/head_tail.rb +11 -0
  22. data/lib/rush/integer_ext.rb +18 -0
  23. data/lib/rush/local.rb +404 -0
  24. data/lib/rush/path.rb +9 -0
  25. data/lib/rush/process.rb +59 -0
  26. data/lib/rush/process_set.rb +62 -0
  27. data/lib/rush/search_results.rb +71 -0
  28. data/lib/rush/shell.rb +118 -0
  29. data/lib/rush/shell/completion.rb +108 -0
  30. data/lib/rush/string_ext.rb +33 -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 +162 -0
  40. data/spec/file_spec.rb +95 -0
  41. data/spec/find_by_spec.rb +58 -0
  42. data/spec/integer_ext_spec.rb +19 -0
  43. data/spec/local_spec.rb +363 -0
  44. data/spec/path_spec.rb +13 -0
  45. data/spec/process_set_spec.rb +50 -0
  46. data/spec/process_spec.rb +89 -0
  47. data/spec/rush_spec.rb +28 -0
  48. data/spec/search_results_spec.rb +44 -0
  49. data/spec/shell_spec.rb +39 -0
  50. data/spec/ssh_tunnel_spec.rb +122 -0
  51. data/spec/string_ext_spec.rb +23 -0
  52. metadata +228 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b99827c73309a2c9e4e34f76f9895a6c8c746319aa1b691e4587f1c500fa4fe7
4
+ data.tar.gz: a0d7944a11b824d44afd3cf11b82c84d8f51c7380c167b8644b977d177a603e3
5
+ SHA512:
6
+ metadata.gz: 2d26505e95f767c97e172d0696137a920c34de97ef77301040c14d8f3470b1b2ea90a10cfd17cf98ecdaa9f732691de09aeddb129755ffa42501d6299e181ed8
7
+ data.tar.gz: 7c7f9bfa17995218345d5b00c8cda4c1bcb12913acaf6178f5f56b0f582bb4538df9752b17411aa7ca9b610f631b5e26ee00f7b71810a88859dd3aafa313ef79
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+
3
+ ruby '~> 2.6.1'
4
+
5
+ gem 'session', '~> 3.2'
6
+ gem 'coolline', '~> 0.5.0'
7
+ gem 'coderay', '~> 1.1', '>= 1.1.2'
8
+ gem 'net-ssh', '~> 5.2'
9
+
10
+ group :development do
11
+ gem 'pry', '~> 0.12.2'
12
+ gem 'rake', '~> 12.3', '>= 12.3.3'
13
+ gem 'jeweler', '~> 2.3', '>= 2.3.9'
14
+ gem 'rspec', '~> 3.8'
15
+ end
@@ -0,0 +1,93 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.4.0)
5
+ builder (3.2.3)
6
+ coderay (1.1.2)
7
+ coolline (0.5.0)
8
+ unicode_utils (~> 1.4)
9
+ descendants_tracker (0.0.4)
10
+ thread_safe (~> 0.3, >= 0.3.1)
11
+ diff-lcs (1.3)
12
+ faraday (0.9.2)
13
+ multipart-post (>= 1.2, < 3)
14
+ git (1.5.0)
15
+ github_api (0.16.0)
16
+ addressable (~> 2.4.0)
17
+ descendants_tracker (~> 0.0.4)
18
+ faraday (~> 0.8, < 0.10)
19
+ hashie (>= 3.4)
20
+ mime-types (>= 1.16, < 3.0)
21
+ oauth2 (~> 1.0)
22
+ hashie (3.6.0)
23
+ highline (2.0.2)
24
+ jeweler (2.3.9)
25
+ builder
26
+ bundler
27
+ git (>= 1.2.5)
28
+ github_api (~> 0.16.0)
29
+ highline (>= 1.6.15)
30
+ nokogiri (>= 1.5.10)
31
+ psych
32
+ rake
33
+ rdoc
34
+ semver2
35
+ jwt (2.2.1)
36
+ method_source (0.9.2)
37
+ mime-types (2.99.3)
38
+ mini_portile2 (2.4.0)
39
+ multi_json (1.13.1)
40
+ multi_xml (0.6.0)
41
+ multipart-post (2.1.1)
42
+ net-ssh (5.2.0)
43
+ nokogiri (1.10.4)
44
+ mini_portile2 (~> 2.4.0)
45
+ oauth2 (1.4.1)
46
+ faraday (>= 0.8, < 0.16.0)
47
+ jwt (>= 1.0, < 3.0)
48
+ multi_json (~> 1.3)
49
+ multi_xml (~> 0.5)
50
+ rack (>= 1.2, < 3)
51
+ pry (0.12.2)
52
+ coderay (~> 1.1.0)
53
+ method_source (~> 0.9.0)
54
+ psych (3.1.0)
55
+ rack (2.0.7)
56
+ rake (12.3.3)
57
+ rdoc (6.2.0)
58
+ rspec (3.8.0)
59
+ rspec-core (~> 3.8.0)
60
+ rspec-expectations (~> 3.8.0)
61
+ rspec-mocks (~> 3.8.0)
62
+ rspec-core (3.8.2)
63
+ rspec-support (~> 3.8.0)
64
+ rspec-expectations (3.8.4)
65
+ diff-lcs (>= 1.2.0, < 2.0)
66
+ rspec-support (~> 3.8.0)
67
+ rspec-mocks (3.8.1)
68
+ diff-lcs (>= 1.2.0, < 2.0)
69
+ rspec-support (~> 3.8.0)
70
+ rspec-support (3.8.2)
71
+ semver2 (3.4.2)
72
+ session (3.2.0)
73
+ thread_safe (0.3.6)
74
+ unicode_utils (1.4.0)
75
+
76
+ PLATFORMS
77
+ ruby
78
+
79
+ DEPENDENCIES
80
+ coderay (~> 1.1, >= 1.1.2)
81
+ coolline (~> 0.5.0)
82
+ jeweler (~> 2.3, >= 2.3.9)
83
+ net-ssh (~> 5.2)
84
+ pry (~> 0.12.2)
85
+ rake (~> 12.3, >= 12.3.3)
86
+ rspec (~> 3.8)
87
+ session (~> 3.2)
88
+
89
+ RUBY VERSION
90
+ ruby 2.6.1p33
91
+
92
+ BUNDLED WITH
93
+ 1.17.3
@@ -0,0 +1,124 @@
1
+ = rush -- manage your unix systems with pure Ruby
2
+
3
+ rush is a unix integration library and an interactive shell which uses pure Ruby syntax. Walk directory trees; create, copy, search, and destroy files; find and kill processes - everything you'd normally do with shell commands, now in the strict and elegant world of Ruby.
4
+
5
+ {<img src="https://travis-ci.org/protolif/rush.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/protolif/rush]
6
+
7
+
8
+ == Install
9
+
10
+ gem install rush3
11
+
12
+
13
+ Or for the bleeding edge:
14
+
15
+ git clone git://github.com/protolif/rush.git
16
+ cd rush
17
+ gem build *.gemspec
18
+ gem install *.gem
19
+
20
+
21
+ If you want the development version, you will need the development headers for ruby (eg. ruby-dev in most package managers) and change that last command to:
22
+
23
+ git clone git://github.com/protolif/rush.git
24
+ cd rush
25
+ bundle install # to get the dependencies
26
+ rake spec # to run the tests
27
+ rake rdoc # to generate a local copy of the docs from your sourcetree (optional)
28
+
29
+ rake install # install your default gem location
30
+
31
+
32
+ To uninstall
33
+
34
+ gem uninstall rush3
35
+
36
+
37
+ == Usage
38
+
39
+ Count the number of classes in your project using bash:
40
+
41
+ find myproj -name \*.rb | xargs grep '^\s*class' | wc -l
42
+
43
+ In rush, this is:
44
+
45
+ myproj['**/*.rb'].search(/^\s*class/).lines.size
46
+
47
+ Pesky stray mongrels? In bash:
48
+
49
+ kill `ps aux | grep mongrel_rails | grep -v grep | cut -c 10-20`
50
+
51
+ In rush:
52
+
53
+ processes.filter(:cmdline => /mongrel_rails/).kill
54
+
55
+ == As a library
56
+
57
+ require 'rubygems'
58
+ require 'rush'
59
+
60
+ file = Rush['/tmp/myfile']
61
+ file.write "hello"
62
+ puts file.contents
63
+ file.destroy
64
+
65
+ puts Rush.my_process.pid
66
+ puts Rush.processes.size
67
+ puts Rush.bash("echo SHELL COMMAND | tr A-Z a-z")
68
+ puts Rush.launch_dir['*.rb'].search(/Rush/).entries.inspect
69
+
70
+ == Invoking the shell
71
+
72
+ Run the "rush" binary to enter the interactive shell.
73
+
74
+ == Remote access and clustering
75
+
76
+ rush can control any number of remote machines from a single location. Copy files or directories between servers as seamlessly as if it was all local.
77
+
78
+ Example of remote access:
79
+
80
+ local = Rush::Box.new('localhost')
81
+ remote = Rush::Box.new('my.remote.server.com')
82
+ local_dir = local['/Users/adam/myproj/']
83
+ remote_dir = remote['/home/myproj/app/']
84
+
85
+ local_dir.copy_to remote_dir
86
+ remote_dir['**/.svn/'].each { |d| d.destroy }
87
+
88
+ Clustering:
89
+
90
+ local_dir = Rush::Box.new('localhost')['/Users/adam/server_logs/'].create
91
+ servers = %w(www1 www2 www3).map { |n| Rush::Box.new(n) }
92
+ servers.each { |s| s['/var/log/nginx/access.log'].copy_to local_dir["#{s.host}_access.log"] }
93
+
94
+ == Reference
95
+
96
+ For more details on syntax and commands, see:
97
+
98
+ * Rush
99
+ * Rush::Entry
100
+ * Rush::File
101
+ * Rush::Dir
102
+ * Rush::Commands
103
+ * Rush::Box
104
+ * Rush::Process
105
+
106
+ == Meta
107
+
108
+ What follows is the meta from the original project, which is no longer maintained.
109
+ The mailinglist was hosted by Google groups, which is no more. Link included for posterity:
110
+ http://groups.google.com/group/ruby-shell
111
+
112
+ The previous maintainer archived their repository.
113
+ The new website for this fork is:
114
+ https://github.com/protolif/rush
115
+
116
+ Created by Adam Wiggins
117
+
118
+ Patches contributed by Chihiro Ito, Gabriel Ware, Michael Schutte, Ricardo Chimal Jr., and Nicholas Schlueter, Pedro Belo, and Martin Kuehl
119
+
120
+ Logo by James Lindenbaum
121
+
122
+ Previously maintained by Sergei Smagin. Now maintained by James Dunn. Ask me if something is unclear: jamesldunnjr@gmail.com
123
+
124
+ Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -0,0 +1,58 @@
1
+ require 'rake'
2
+ require 'jeweler'
3
+
4
+ Jeweler::Tasks.new do |s|
5
+ s.name = "rush3"
6
+ s.summary = "A Ruby replacement for bash+ssh."
7
+ s.description = "A Ruby replacement for bash+ssh, providing both an interactive shell and a library. Manage both local and remote unix systems from a single client."
8
+ s.authors = ["Adam Wiggins", "Sergei Smagin", "James Dunn"]
9
+ s.email = "jamesldunnjr@gmail.com"
10
+ s.homepage = "https://github.com/protolif/rush"
11
+ s.licenses = ['MIT']
12
+ s.executables = [ "rush", "rushd" ]
13
+ s.version = "3.0.0"
14
+ # s.has_rdoc = true
15
+ # Deprecated with no replacement on 2018-12-01.
16
+
17
+ s.files = FileList["[A-Z]*", "{bin,lib,spec}/**/*"]
18
+ end
19
+
20
+ Jeweler::GemcutterTasks.new
21
+
22
+ ######################################################
23
+
24
+ require 'rspec/core/rake_task'
25
+
26
+ desc "Run all specs"
27
+ RSpec::Core::RakeTask.new('spec') do |t|
28
+ t.pattern = 'spec/*_spec.rb'
29
+ end
30
+
31
+ desc "Print specdocs"
32
+ RSpec::Core::RakeTask.new(:doc) do |t|
33
+ t.pattern = 'spec/*_spec.rb'
34
+ t.rspec_opts = ["--format", "specdoc", "--dry-run"]
35
+ end
36
+
37
+ desc "Run all examples with RCov"
38
+ RSpec::Core::RakeTask.new('rcov') do |t|
39
+ t.pattern = 'spec/*_spec.rb'
40
+ t.rcov = true
41
+ t.rcov_opts = ['--exclude', 'examples']
42
+ end
43
+
44
+ task :default => :spec
45
+
46
+ ######################################################
47
+
48
+ require 'rdoc/task'
49
+
50
+ Rake::RDocTask.new do |t|
51
+ t.rdoc_dir = 'rdoc'
52
+ t.title = "rush, a Ruby replacement for bash+ssh"
53
+ t.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
54
+ t.options << '--charset' << 'utf-8'
55
+ t.rdoc_files.include('README.rdoc')
56
+ t.rdoc_files.include('lib/rush.rb')
57
+ t.rdoc_files.include('lib/rush/*.rb')
58
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.10.0
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/rush'
4
+ require_relative '../lib/rush/shell'
5
+
6
+ shell = Rush::Shell.new
7
+
8
+ if ARGV.size > 0
9
+ shell.execute ARGV.join(' ')
10
+ else
11
+ shell.run
12
+ end
13
+
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative __dir__ + '/../lib/rush'
4
+ require_relative __dir__ + '/../lib/rush/server'
5
+
6
+ RushServer.new.run
7
+
@@ -0,0 +1,91 @@
1
+ require 'etc' # get info from /etc
2
+
3
+ # The top-level Rush module has some convenience methods for accessing the
4
+ # local box.
5
+ module Rush
6
+ # Access the root filesystem of the local box.
7
+ #
8
+ # @param key [String] relative path.
9
+ # @example
10
+ # Rush['/etc/hosts'].contents
11
+ #
12
+ def self.[](key)
13
+ box[key]
14
+ end
15
+
16
+ # Create a dir object from the path of a provided file.
17
+ #
18
+ # @param filename [String] path that should be created.
19
+ # @example
20
+ # Rush.dir(__FILE__).files
21
+ #
22
+ def self.dir(filename)
23
+ box[::File.expand_path(::File.dirname(filename)) + '/']
24
+ end
25
+
26
+ # Create a dir object based on the shell's current working directory at the
27
+ # time the program was run.
28
+ #
29
+ # @example
30
+ # Rush.launch_dir.files
31
+ #
32
+ def self.launch_dir
33
+ box[::Dir.pwd + '/']
34
+ end
35
+
36
+ # Run a bash command in the root of the local machine. Equivalent to
37
+ # Rush::Box.new.bash.
38
+ def self.bash(command, options={})
39
+ box.bash(command, options)
40
+ end
41
+
42
+ # Pull the process list for the local machine.
43
+ #
44
+ # @example
45
+ # Rush.processes.filter(:cmdline => /ruby/)
46
+ #
47
+ def self.processes
48
+ box.processes
49
+ end
50
+
51
+ # Get the process object for this program's PID.
52
+ #
53
+ # @example
54
+ # puts "I'm using #{Rush.my_process.mem} blocks of memory"
55
+ #
56
+ def self.my_process
57
+ box.processes.filter(:pid => ::Process.pid).first
58
+ end
59
+
60
+ # Create a box object for localhost.
61
+ def self.box
62
+ @@box = Rush::Box.new
63
+ end
64
+
65
+ # Quote a path for use in backticks, say.
66
+ def self.quote(path)
67
+ path.gsub(/(?=[^a-zA-Z0-9_.\/\-\x7F-\xFF\n])/n, '\\').gsub(/\n/, "'\n'").sub(/^$/, "''")
68
+ end
69
+ end
70
+
71
+ module Rush::Connection; end
72
+
73
+ require_relative 'rush/exceptions'
74
+ require_relative 'rush/config'
75
+ require_relative 'rush/commands'
76
+ require_relative 'rush/access'
77
+ require_relative 'rush/path'
78
+ require_relative 'rush/entry'
79
+ require_relative 'rush/file'
80
+ require_relative 'rush/dir'
81
+ require_relative 'rush/search_results'
82
+ require_relative 'rush/head_tail'
83
+ require_relative 'rush/find_by'
84
+ require_relative 'rush/string_ext'
85
+ require_relative 'rush/integer_ext'
86
+ require_relative 'rush/array_ext'
87
+ require_relative 'rush/process'
88
+ require_relative 'rush/process_set'
89
+ require_relative 'rush/local'
90
+ require_relative 'rush/box'
91
+ require_relative 'rush/embeddable_shell'
@@ -0,0 +1,121 @@
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
+ #
4
+ class Rush::Access
5
+ ROLES = %w(user group other)
6
+ PERMISSIONS = %w(read write execute)
7
+ ACCESS_UNITS = ROLES.product(PERMISSIONS).
8
+ map { |r, p| "#{r}_can_#{p}".to_sym }
9
+
10
+ attr_accessor *ACCESS_UNITS
11
+
12
+ def self.roles
13
+ ROLES
14
+ end
15
+
16
+ def self.permissions
17
+ PERMISSIONS
18
+ end
19
+
20
+ def parse(options)
21
+ options.each do |key, value|
22
+ next unless m = key.to_s.match(/(.*)_can$/)
23
+ key = m[1].to_sym
24
+ roles = extract_list('role', key, self.class.roles)
25
+ perms = extract_list('permission', value, self.class.permissions)
26
+ set_matrix(perms, roles)
27
+ end
28
+ self
29
+ end
30
+
31
+ def self.parse(options)
32
+ new.parse(options)
33
+ end
34
+
35
+ def apply(full_path)
36
+ FileUtils.chmod(octal_permissions, full_path)
37
+ rescue Errno::ENOENT
38
+ raise Rush::DoesNotExist, full_path
39
+ end
40
+
41
+ def to_hash
42
+ ACCESS_UNITS.inject({}) do |hash, unit|
43
+ hash.merge(unit => send(unit) ? 1 : 0)
44
+ end
45
+ end
46
+
47
+ def display_hash
48
+ to_hash.select { |_, v| v == 1 }.
49
+ inject({}) { |r, (k, _)| r.merge k => true }
50
+ end
51
+
52
+ def from_hash(hash)
53
+ ACCESS_UNITS.each do |unit|
54
+ send("#{unit}=".to_sym, hash[unit].to_i == 1 ? true : false)
55
+ end
56
+ self
57
+ end
58
+
59
+ def self.from_hash(hash)
60
+ new.from_hash(hash)
61
+ end
62
+
63
+ def octal_permissions
64
+ perms = [ 0, 0, 0 ]
65
+ perms[0] += 4 if user_can_read
66
+ perms[0] += 2 if user_can_write
67
+ perms[0] += 1 if user_can_execute
68
+
69
+ perms[1] += 4 if group_can_read
70
+ perms[1] += 2 if group_can_write
71
+ perms[1] += 1 if group_can_execute
72
+
73
+ perms[2] += 4 if other_can_read
74
+ perms[2] += 2 if other_can_write
75
+ perms[2] += 1 if other_can_execute
76
+
77
+ eval("0" + perms.join)
78
+ end
79
+
80
+ def from_octal(mode)
81
+ perms = octal_integer_array(mode)
82
+
83
+ self.user_can_read = (perms[0] & 4) > 0 ? true : false
84
+ self.user_can_write = (perms[0] & 2) > 0 ? true : false
85
+ self.user_can_execute = (perms[0] & 1) > 0 ? true : false
86
+
87
+ self.group_can_read = (perms[1] & 4) > 0 ? true : false
88
+ self.group_can_write = (perms[1] & 2) > 0 ? true : false
89
+ self.group_can_execute = (perms[1] & 1) > 0 ? true : false
90
+
91
+ self.other_can_read = (perms[2] & 4) > 0 ? true : false
92
+ self.other_can_write = (perms[2] & 2) > 0 ? true : false
93
+ self.other_can_execute = (perms[2] & 1) > 0 ? true : false
94
+
95
+ self
96
+ end
97
+
98
+ def octal_integer_array(mode)
99
+ mode %= 01000 # filter out everything but the bottom three digits
100
+ mode = sprintf("%o", mode) # convert to string
101
+ mode.split("").map { |p| p.to_i } # and finally, array of integers
102
+ end
103
+
104
+ def set_matrix(perms, roles)
105
+ ROLES.product(PERMISSIONS).
106
+ select { |r, p| perms.include?(p) && roles.include?(r) }.
107
+ map { |r, p| "#{r}_can_#{p}=".to_sym }.
108
+ each { |unit| send unit, true }
109
+ end
110
+
111
+ def extract_list(type, value, choices)
112
+ list = parts_from(value)
113
+ list.each do |value|
114
+ raise(Rush::BadAccessSpecifier, "Unrecognized #{type}: #{value}") unless choices.include? value
115
+ end
116
+ end
117
+
118
+ def parts_from(value)
119
+ value.to_s.split('_').reject { |r| r == 'and' }
120
+ end
121
+ end