dysinger-rush 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 +65 -0
 - data/bin/rush +13 -0
 - data/bin/rushd +7 -0
 - data/lib/rush.rb +27 -0
 - data/lib/rush/access.rb +130 -0
 - data/lib/rush/array_ext.rb +19 -0
 - data/lib/rush/box.rb +112 -0
 - data/lib/rush/commands.rb +55 -0
 - data/lib/rush/config.rb +154 -0
 - data/lib/rush/dir.rb +158 -0
 - data/lib/rush/embeddable_shell.rb +26 -0
 - data/lib/rush/entry.rb +178 -0
 - data/lib/rush/exceptions.rb +31 -0
 - data/lib/rush/file.rb +77 -0
 - data/lib/rush/find_by.rb +39 -0
 - data/lib/rush/fixnum_ext.rb +18 -0
 - data/lib/rush/head_tail.rb +11 -0
 - data/lib/rush/local.rb +374 -0
 - data/lib/rush/process.rb +55 -0
 - data/lib/rush/process_set.rb +62 -0
 - data/lib/rush/remote.rb +152 -0
 - data/lib/rush/search_results.rb +58 -0
 - data/lib/rush/server.rb +117 -0
 - data/lib/rush/shell.rb +148 -0
 - data/lib/rush/ssh_tunnel.rb +122 -0
 - data/lib/rush/string_ext.rb +3 -0
 - data/spec/access_spec.rb +134 -0
 - data/spec/array_ext_spec.rb +15 -0
 - data/spec/base.rb +24 -0
 - data/spec/box_spec.rb +64 -0
 - data/spec/commands_spec.rb +47 -0
 - data/spec/config_spec.rb +108 -0
 - data/spec/dir_spec.rb +159 -0
 - data/spec/embeddable_shell_spec.rb +17 -0
 - data/spec/entry_spec.rb +129 -0
 - data/spec/file_spec.rb +79 -0
 - data/spec/find_by_spec.rb +58 -0
 - data/spec/fixnum_ext_spec.rb +19 -0
 - data/spec/local_spec.rb +313 -0
 - data/spec/process_set_spec.rb +50 -0
 - data/spec/process_spec.rb +73 -0
 - data/spec/remote_spec.rb +135 -0
 - data/spec/search_results_spec.rb +44 -0
 - data/spec/shell_spec.rb +12 -0
 - data/spec/ssh_tunnel_spec.rb +122 -0
 - data/spec/string_ext_spec.rb +23 -0
 - metadata +126 -0
 
| 
         @@ -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
         
     | 
    
        data/lib/rush/remote.rb
    ADDED
    
    | 
         @@ -0,0 +1,152 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # This class it the mirror of Rush::Connection::Local.  A Rush::Box which is
         
     | 
| 
      
 4 
     | 
    
         
            +
            # not localhost has a remote connection, which it can use to convert method
         
     | 
| 
      
 5 
     | 
    
         
            +
            # calls to text suitable for transmission across the wire.
         
     | 
| 
      
 6 
     | 
    
         
            +
            #
         
     | 
| 
      
 7 
     | 
    
         
            +
            # This is an internal class that does not need to be accessed in normal use of
         
     | 
| 
      
 8 
     | 
    
         
            +
            # the rush shell or library.
         
     | 
| 
      
 9 
     | 
    
         
            +
            class Rush::Connection::Remote
         
     | 
| 
      
 10 
     | 
    
         
            +
            	attr_reader :host, :tunnel
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            	def initialize(host)
         
     | 
| 
      
 13 
     | 
    
         
            +
            		@host = host
         
     | 
| 
      
 14 
     | 
    
         
            +
            		@tunnel = Rush::SshTunnel.new(host)
         
     | 
| 
      
 15 
     | 
    
         
            +
            	end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            	def write_file(full_path, contents)
         
     | 
| 
      
 18 
     | 
    
         
            +
            		transmit(:action => 'write_file', :full_path => full_path, :payload => contents)
         
     | 
| 
      
 19 
     | 
    
         
            +
            	end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            	def file_contents(full_path)
         
     | 
| 
      
 22 
     | 
    
         
            +
            		transmit(:action => 'file_contents', :full_path => full_path)
         
     | 
| 
      
 23 
     | 
    
         
            +
            	end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            	def destroy(full_path)
         
     | 
| 
      
 26 
     | 
    
         
            +
            		transmit(:action => 'destroy', :full_path => full_path)
         
     | 
| 
      
 27 
     | 
    
         
            +
            	end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            	def purge(full_path)
         
     | 
| 
      
 30 
     | 
    
         
            +
            		transmit(:action => 'purge', :full_path => full_path)
         
     | 
| 
      
 31 
     | 
    
         
            +
            	end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            	def create_dir(full_path)
         
     | 
| 
      
 34 
     | 
    
         
            +
            		transmit(:action => 'create_dir', :full_path => full_path)
         
     | 
| 
      
 35 
     | 
    
         
            +
            	end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            	def rename(path, name, new_name)
         
     | 
| 
      
 38 
     | 
    
         
            +
            		transmit(:action => 'rename', :path => path, :name => name, :new_name => 'new_name')
         
     | 
| 
      
 39 
     | 
    
         
            +
            	end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            	def copy(src, dst)
         
     | 
| 
      
 42 
     | 
    
         
            +
            		transmit(:action => 'copy', :src => src, :dst => dst)
         
     | 
| 
      
 43 
     | 
    
         
            +
            	end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            	def read_archive(full_path)
         
     | 
| 
      
 46 
     | 
    
         
            +
            		transmit(:action => 'read_archive', :full_path => full_path)
         
     | 
| 
      
 47 
     | 
    
         
            +
            	end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            	def write_archive(archive, dir)
         
     | 
| 
      
 50 
     | 
    
         
            +
            		transmit(:action => 'write_archive', :dir => dir, :payload => archive)
         
     | 
| 
      
 51 
     | 
    
         
            +
            	end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            	def index(base_path, glob)
         
     | 
| 
      
 54 
     | 
    
         
            +
            		transmit(:action => 'index', :base_path => base_path, :glob => glob).split("\n")
         
     | 
| 
      
 55 
     | 
    
         
            +
            	end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            	def stat(full_path)
         
     | 
| 
      
 58 
     | 
    
         
            +
            		YAML.load(transmit(:action => 'stat', :full_path => full_path))
         
     | 
| 
      
 59 
     | 
    
         
            +
            	end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            	def set_access(full_path, access)
         
     | 
| 
      
 62 
     | 
    
         
            +
            		transmit access.to_hash.merge(:action => 'set_access', :full_path => full_path)
         
     | 
| 
      
 63 
     | 
    
         
            +
            	end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            	def size(full_path)
         
     | 
| 
      
 66 
     | 
    
         
            +
            		transmit(:action => 'size', :full_path => full_path).to_i
         
     | 
| 
      
 67 
     | 
    
         
            +
            	end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            	def processes
         
     | 
| 
      
 70 
     | 
    
         
            +
            		YAML.load(transmit(:action => 'processes'))
         
     | 
| 
      
 71 
     | 
    
         
            +
            	end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            	def process_alive(pid)
         
     | 
| 
      
 74 
     | 
    
         
            +
            		transmit(:action => 'process_alive', :pid => pid)
         
     | 
| 
      
 75 
     | 
    
         
            +
            	end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
            	def kill_process(pid)
         
     | 
| 
      
 78 
     | 
    
         
            +
            		transmit(:action => 'kill_process', :pid => pid)
         
     | 
| 
      
 79 
     | 
    
         
            +
            	end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            	def bash(command, user, background)
         
     | 
| 
      
 82 
     | 
    
         
            +
            		transmit(:action => 'bash', :payload => command, :user => user, :background => background)
         
     | 
| 
      
 83 
     | 
    
         
            +
            	end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            	# Given a hash of parameters (converted by the method call on the connection
         
     | 
| 
      
 86 
     | 
    
         
            +
            	# object), send it across the wire to the RushServer listening on the other
         
     | 
| 
      
 87 
     | 
    
         
            +
            	# side.  Uses http basic auth, with credentials fetched from the Rush::Config.
         
     | 
| 
      
 88 
     | 
    
         
            +
            	def transmit(params)
         
     | 
| 
      
 89 
     | 
    
         
            +
            		ensure_tunnel
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
            		require 'net/http'
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            		payload = params.delete(:payload)
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
            		uri = "/?"
         
     | 
| 
      
 96 
     | 
    
         
            +
            		params.each do |key, value|
         
     | 
| 
      
 97 
     | 
    
         
            +
            			uri += "#{key}=#{value}&"
         
     | 
| 
      
 98 
     | 
    
         
            +
            		end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
            		req = Net::HTTP::Post.new(uri)
         
     | 
| 
      
 101 
     | 
    
         
            +
            		req.basic_auth config.credentials_user, config.credentials_password
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
            		Net::HTTP.start(tunnel.host, tunnel.port) do |http|
         
     | 
| 
      
 104 
     | 
    
         
            +
            			res = http.request(req, payload)
         
     | 
| 
      
 105 
     | 
    
         
            +
            			process_result(res.code, res.body)
         
     | 
| 
      
 106 
     | 
    
         
            +
            		end
         
     | 
| 
      
 107 
     | 
    
         
            +
            	rescue EOFError
         
     | 
| 
      
 108 
     | 
    
         
            +
            		raise Rush::RushdNotRunning
         
     | 
| 
      
 109 
     | 
    
         
            +
            	end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
            	# Take the http result of a transmit and raise an error, or return the body
         
     | 
| 
      
 112 
     | 
    
         
            +
            	# of the result when valid.
         
     | 
| 
      
 113 
     | 
    
         
            +
            	def process_result(code, body)
         
     | 
| 
      
 114 
     | 
    
         
            +
            		raise Rush::NotAuthorized if code == "401"
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
            		if code == "400"	
         
     | 
| 
      
 117 
     | 
    
         
            +
            			klass, message = parse_exception(body)
         
     | 
| 
      
 118 
     | 
    
         
            +
            			raise klass, "#{host}:#{message}"
         
     | 
| 
      
 119 
     | 
    
         
            +
            		end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
            		raise Rush::FailedTransmit if code != "200"
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
            		body
         
     | 
| 
      
 124 
     | 
    
         
            +
            	end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
            	# Parse an exception returned from the server, with the class name on the
         
     | 
| 
      
 127 
     | 
    
         
            +
            	# first line and the message on the second.
         
     | 
| 
      
 128 
     | 
    
         
            +
            	def parse_exception(body)
         
     | 
| 
      
 129 
     | 
    
         
            +
            		klass, message = body.split("\n", 2)
         
     | 
| 
      
 130 
     | 
    
         
            +
            		raise "invalid exception class: #{klass}" unless klass.match(/^Rush::[A-Za-z]+$/)
         
     | 
| 
      
 131 
     | 
    
         
            +
            		klass = Object.module_eval(klass)
         
     | 
| 
      
 132 
     | 
    
         
            +
            		[ klass, message.strip ]
         
     | 
| 
      
 133 
     | 
    
         
            +
            	end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
            	# Set up the tunnel if it is not already running.
         
     | 
| 
      
 136 
     | 
    
         
            +
            	def ensure_tunnel(options={})
         
     | 
| 
      
 137 
     | 
    
         
            +
            		tunnel.ensure_tunnel(options)
         
     | 
| 
      
 138 
     | 
    
         
            +
            	end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
            	# Remote connections are alive when the box on the other end is responding
         
     | 
| 
      
 141 
     | 
    
         
            +
            	# to commands.
         
     | 
| 
      
 142 
     | 
    
         
            +
            	def alive?
         
     | 
| 
      
 143 
     | 
    
         
            +
            		index('/', 'alive_check')
         
     | 
| 
      
 144 
     | 
    
         
            +
            		true
         
     | 
| 
      
 145 
     | 
    
         
            +
            	rescue
         
     | 
| 
      
 146 
     | 
    
         
            +
            		false
         
     | 
| 
      
 147 
     | 
    
         
            +
            	end
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
            	def config
         
     | 
| 
      
 150 
     | 
    
         
            +
            		@config ||= Rush::Config.new
         
     | 
| 
      
 151 
     | 
    
         
            +
            	end
         
     | 
| 
      
 152 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # An instance of this class is returned by Rush::Commands#search.  It contains
         
     | 
| 
      
 2 
     | 
    
         
            +
            # both the list of entries which matched the search, as well as the raw line
         
     | 
| 
      
 3 
     | 
    
         
            +
            # matches.  These methods get equivalent functionality to "grep -l" and "grep -h".
         
     | 
| 
      
 4 
     | 
    
         
            +
            #
         
     | 
| 
      
 5 
     | 
    
         
            +
            # SearchResults mixes in Rush::Commands so that you can chain multiple searches
         
     | 
| 
      
 6 
     | 
    
         
            +
            # or do file operations on the resulting entries.
         
     | 
| 
      
 7 
     | 
    
         
            +
            #
         
     | 
| 
      
 8 
     | 
    
         
            +
            # Examples:
         
     | 
| 
      
 9 
     | 
    
         
            +
            #
         
     | 
| 
      
 10 
     | 
    
         
            +
            #   myproj['**/*.rb'].search(/class/).entries.size
         
     | 
| 
      
 11 
     | 
    
         
            +
            #   myproj['**/*.rb'].search(/class/).lines.size
         
     | 
| 
      
 12 
     | 
    
         
            +
            #   myproj['**/*.rb'].search(/class/).copy_to other_dir
         
     | 
| 
      
 13 
     | 
    
         
            +
            class Rush::SearchResults
         
     | 
| 
      
 14 
     | 
    
         
            +
            	attr_reader :entries, :lines, :entries_with_lines, :pattern
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            	# Make a blank container.  Track the pattern so that we can colorize the
         
     | 
| 
      
 17 
     | 
    
         
            +
            	# output to show what was matched.
         
     | 
| 
      
 18 
     | 
    
         
            +
            	def initialize(pattern)
         
     | 
| 
      
 19 
     | 
    
         
            +
            		# Duplication of data, but this lets us return everything in the exact
         
     | 
| 
      
 20 
     | 
    
         
            +
            		# order it was received.
         
     | 
| 
      
 21 
     | 
    
         
            +
            		@pattern = pattern
         
     | 
| 
      
 22 
     | 
    
         
            +
            		@entries = []
         
     | 
| 
      
 23 
     | 
    
         
            +
            		@entries_with_lines = {}
         
     | 
| 
      
 24 
     | 
    
         
            +
            		@lines = []
         
     | 
| 
      
 25 
     | 
    
         
            +
            	end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            	# Add a Rush::Entry and the array of string matches.
         
     | 
| 
      
 28 
     | 
    
         
            +
            	def add(entry, lines)
         
     | 
| 
      
 29 
     | 
    
         
            +
            		# this assumes that entry is unique
         
     | 
| 
      
 30 
     | 
    
         
            +
            		@entries << entry
         
     | 
| 
      
 31 
     | 
    
         
            +
            		@entries_with_lines[entry] = lines
         
     | 
| 
      
 32 
     | 
    
         
            +
            		@lines += lines
         
     | 
| 
      
 33 
     | 
    
         
            +
            	end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            	include Rush::Commands
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            	def each(&block)
         
     | 
| 
      
 38 
     | 
    
         
            +
            		@entries.each(&block)
         
     | 
| 
      
 39 
     | 
    
         
            +
            	end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            	include Enumerable
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            	def colorize(line)
         
     | 
| 
      
 44 
     | 
    
         
            +
            		lowlight + line.gsub(/(#{pattern.source})/, "#{hilight}\\1#{lowlight}") + normal
         
     | 
| 
      
 45 
     | 
    
         
            +
            	end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            	def hilight
         
     | 
| 
      
 48 
     | 
    
         
            +
            		"\e[34;1m"
         
     | 
| 
      
 49 
     | 
    
         
            +
            	end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            	def lowlight
         
     | 
| 
      
 52 
     | 
    
         
            +
            		"\e[37;2m"
         
     | 
| 
      
 53 
     | 
    
         
            +
            	end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            	def normal
         
     | 
| 
      
 56 
     | 
    
         
            +
            		"\e[0m"
         
     | 
| 
      
 57 
     | 
    
         
            +
            	end
         
     | 
| 
      
 58 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/rush/server.rb
    ADDED
    
    | 
         @@ -0,0 +1,117 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'mongrel'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'base64'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            # Mongrel handler that translates the incoming HTTP request into a
         
     | 
| 
      
 6 
     | 
    
         
            +
            # Rush::Connection::Local call.  The results are sent back across the wire to
         
     | 
| 
      
 7 
     | 
    
         
            +
            # be decoded by Rush::Connection::Remote on the other side.
         
     | 
| 
      
 8 
     | 
    
         
            +
            class RushHandler < Mongrel::HttpHandler
         
     | 
| 
      
 9 
     | 
    
         
            +
            	def process(request, response)
         
     | 
| 
      
 10 
     | 
    
         
            +
            		params = {}
         
     | 
| 
      
 11 
     | 
    
         
            +
            		request.params['QUERY_STRING'].split("?").last.split("&").each do |tuple|
         
     | 
| 
      
 12 
     | 
    
         
            +
            			key, value = tuple.split("=")
         
     | 
| 
      
 13 
     | 
    
         
            +
            			params[key.to_sym] = value
         
     | 
| 
      
 14 
     | 
    
         
            +
            		end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            		unless authorize(request.params['HTTP_AUTHORIZATION'])
         
     | 
| 
      
 17 
     | 
    
         
            +
            			response.start(401) do |head, out|
         
     | 
| 
      
 18 
     | 
    
         
            +
            			end
         
     | 
| 
      
 19 
     | 
    
         
            +
            		else
         
     | 
| 
      
 20 
     | 
    
         
            +
            			payload = request.body.read
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            			without_action = params
         
     | 
| 
      
 23 
     | 
    
         
            +
            			without_action.delete(params[:action])
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            			msg = sprintf "%-20s", params[:action]
         
     | 
| 
      
 26 
     | 
    
         
            +
            			msg += without_action.inspect
         
     | 
| 
      
 27 
     | 
    
         
            +
            			msg += " + #{payload.size} bytes of payload" if payload.size > 0
         
     | 
| 
      
 28 
     | 
    
         
            +
            			log msg
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            			params[:payload] = payload
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            			begin
         
     | 
| 
      
 33 
     | 
    
         
            +
            				result = box.connection.receive(params)
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            				response.start(200) do |head, out|
         
     | 
| 
      
 36 
     | 
    
         
            +
            					out.write result
         
     | 
| 
      
 37 
     | 
    
         
            +
            				end
         
     | 
| 
      
 38 
     | 
    
         
            +
            			rescue Rush::Exception => e
         
     | 
| 
      
 39 
     | 
    
         
            +
            				response.start(400) do |head, out|
         
     | 
| 
      
 40 
     | 
    
         
            +
            					out.write "#{e.class}\n#{e.message}\n"
         
     | 
| 
      
 41 
     | 
    
         
            +
            				end
         
     | 
| 
      
 42 
     | 
    
         
            +
            			end
         
     | 
| 
      
 43 
     | 
    
         
            +
            		end
         
     | 
| 
      
 44 
     | 
    
         
            +
            	rescue Exception => e
         
     | 
| 
      
 45 
     | 
    
         
            +
            		log e.full_display
         
     | 
| 
      
 46 
     | 
    
         
            +
            	end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            	def authorize(auth)
         
     | 
| 
      
 49 
     | 
    
         
            +
            		unless m = auth.match(/^Basic (.+)$/)
         
     | 
| 
      
 50 
     | 
    
         
            +
            			log "Request with no authorization data"
         
     | 
| 
      
 51 
     | 
    
         
            +
            			return false
         
     | 
| 
      
 52 
     | 
    
         
            +
            		end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            		decoded = Base64.decode64(m[1])
         
     | 
| 
      
 55 
     | 
    
         
            +
            		user, password = decoded.split(':', 2)
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            		if user.nil? or user.length == 0 or password.nil? or password.length == 0
         
     | 
| 
      
 58 
     | 
    
         
            +
            			log "Malformed user or password"
         
     | 
| 
      
 59 
     | 
    
         
            +
            			return false
         
     | 
| 
      
 60 
     | 
    
         
            +
            		end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            		if password == config.passwords[user]
         
     | 
| 
      
 63 
     | 
    
         
            +
            			return true
         
     | 
| 
      
 64 
     | 
    
         
            +
            		else
         
     | 
| 
      
 65 
     | 
    
         
            +
            			log "Access denied to #{user}"
         
     | 
| 
      
 66 
     | 
    
         
            +
            			return false
         
     | 
| 
      
 67 
     | 
    
         
            +
            		end
         
     | 
| 
      
 68 
     | 
    
         
            +
            	end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            	def box
         
     | 
| 
      
 71 
     | 
    
         
            +
            		@box ||= Rush::Box.new('localhost')
         
     | 
| 
      
 72 
     | 
    
         
            +
            	end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            	def config
         
     | 
| 
      
 75 
     | 
    
         
            +
            		@config ||= Rush::Config.new
         
     | 
| 
      
 76 
     | 
    
         
            +
            	end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            	def log(msg)
         
     | 
| 
      
 79 
     | 
    
         
            +
            		File.open('rushd.log', 'a') do |f|
         
     | 
| 
      
 80 
     | 
    
         
            +
            			f.puts "#{Time.now.strftime('%Y-%m-%d %H:%I:%S')} :: #{msg}"
         
     | 
| 
      
 81 
     | 
    
         
            +
            		end
         
     | 
| 
      
 82 
     | 
    
         
            +
            	end
         
     | 
| 
      
 83 
     | 
    
         
            +
            end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            # A container class to run the Mongrel server for rushd.
         
     | 
| 
      
 86 
     | 
    
         
            +
            class RushServer
         
     | 
| 
      
 87 
     | 
    
         
            +
            	def run
         
     | 
| 
      
 88 
     | 
    
         
            +
            		host = "127.0.0.1"
         
     | 
| 
      
 89 
     | 
    
         
            +
            		port = Rush::Config::DefaultPort
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
            		rushd = RushHandler.new
         
     | 
| 
      
 92 
     | 
    
         
            +
            		rushd.log "rushd listening on #{host}:#{port}"
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
            		h = Mongrel::HttpServer.new(host, port)
         
     | 
| 
      
 95 
     | 
    
         
            +
            		h.register("/", rushd)
         
     | 
| 
      
 96 
     | 
    
         
            +
            		h.run.join
         
     | 
| 
      
 97 
     | 
    
         
            +
            	end
         
     | 
| 
      
 98 
     | 
    
         
            +
            end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
            class Exception
         
     | 
| 
      
 101 
     | 
    
         
            +
            	def full_display
         
     | 
| 
      
 102 
     | 
    
         
            +
            		out = []
         
     | 
| 
      
 103 
     | 
    
         
            +
            		out << "Exception #{self.class} => #{self}"
         
     | 
| 
      
 104 
     | 
    
         
            +
            		out << "Backtrace:"
         
     | 
| 
      
 105 
     | 
    
         
            +
            		out << self.filtered_backtrace.collect do |t|
         
     | 
| 
      
 106 
     | 
    
         
            +
            			"   #{t}"
         
     | 
| 
      
 107 
     | 
    
         
            +
            		end
         
     | 
| 
      
 108 
     | 
    
         
            +
            		out << ""
         
     | 
| 
      
 109 
     | 
    
         
            +
            		out.join("\n")
         
     | 
| 
      
 110 
     | 
    
         
            +
            	end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
            	def filtered_backtrace
         
     | 
| 
      
 113 
     | 
    
         
            +
            		backtrace.reject do |bt|
         
     | 
| 
      
 114 
     | 
    
         
            +
            			bt.match(/^\/usr\//)
         
     | 
| 
      
 115 
     | 
    
         
            +
            		end
         
     | 
| 
      
 116 
     | 
    
         
            +
            	end
         
     | 
| 
      
 117 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/rush/shell.rb
    ADDED
    
    | 
         @@ -0,0 +1,148 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'readline'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # Rush::Shell is used to create an interactive shell.  It is invoked by the rush binary.
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Rush
         
     | 
| 
      
 5 
     | 
    
         
            +
            	class Shell
         
     | 
| 
      
 6 
     | 
    
         
            +
            		attr_accessor :suppress_output
         
     | 
| 
      
 7 
     | 
    
         
            +
            		# Set up the user's environment, including a pure binding into which
         
     | 
| 
      
 8 
     | 
    
         
            +
            		# env.rb and commands.rb are mixed.
         
     | 
| 
      
 9 
     | 
    
         
            +
            		def initialize
         
     | 
| 
      
 10 
     | 
    
         
            +
            			root = Rush::Dir.new('/')
         
     | 
| 
      
 11 
     | 
    
         
            +
            			home = Rush::Dir.new(ENV['HOME']) if ENV['HOME']
         
     | 
| 
      
 12 
     | 
    
         
            +
            			pwd = Rush::Dir.new(ENV['PWD']) if ENV['PWD']
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            			@config = Rush::Config.new
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            			@config.load_history.each do |item|
         
     | 
| 
      
 17 
     | 
    
         
            +
            				Readline::HISTORY.push(item)
         
     | 
| 
      
 18 
     | 
    
         
            +
            			end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            			Readline.basic_word_break_characters = ""
         
     | 
| 
      
 21 
     | 
    
         
            +
            			Readline.completion_append_character = nil
         
     | 
| 
      
 22 
     | 
    
         
            +
            			Readline.completion_proc = completion_proc
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            			@box = Rush::Box.new
         
     | 
| 
      
 25 
     | 
    
         
            +
            			@pure_binding = @box.instance_eval "binding"
         
     | 
| 
      
 26 
     | 
    
         
            +
            			$last_res = nil
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            			eval @config.load_env, @pure_binding
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            			commands = @config.load_commands
         
     | 
| 
      
 31 
     | 
    
         
            +
            			Rush::Dir.class_eval commands
         
     | 
| 
      
 32 
     | 
    
         
            +
            			Array.class_eval commands
         
     | 
| 
      
 33 
     | 
    
         
            +
            		end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            		# Run a single command.
         
     | 
| 
      
 36 
     | 
    
         
            +
            		def execute(cmd)
         
     | 
| 
      
 37 
     | 
    
         
            +
            			res = eval(cmd, @pure_binding)
         
     | 
| 
      
 38 
     | 
    
         
            +
            			$last_res = res
         
     | 
| 
      
 39 
     | 
    
         
            +
            			eval("_ = $last_res", @pure_binding)
         
     | 
| 
      
 40 
     | 
    
         
            +
            			print_result res
         
     | 
| 
      
 41 
     | 
    
         
            +
            		rescue Rush::Exception => e
         
     | 
| 
      
 42 
     | 
    
         
            +
            			puts "Exception #{e.class} -> #{e.message}"
         
     | 
| 
      
 43 
     | 
    
         
            +
            		rescue ::Exception => e
         
     | 
| 
      
 44 
     | 
    
         
            +
            			puts "Exception #{e.class} -> #{e.message}"
         
     | 
| 
      
 45 
     | 
    
         
            +
            			e.backtrace.each do |t|
         
     | 
| 
      
 46 
     | 
    
         
            +
            				puts "   #{::File.expand_path(t)}"
         
     | 
| 
      
 47 
     | 
    
         
            +
            			end
         
     | 
| 
      
 48 
     | 
    
         
            +
            		end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            		# Run the interactive shell using readline.
         
     | 
| 
      
 51 
     | 
    
         
            +
            		def run
         
     | 
| 
      
 52 
     | 
    
         
            +
            			loop do
         
     | 
| 
      
 53 
     | 
    
         
            +
            				cmd = Readline.readline('rush> ')
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            				finish if cmd.nil? or cmd == 'exit'
         
     | 
| 
      
 56 
     | 
    
         
            +
            				next if cmd == ""
         
     | 
| 
      
 57 
     | 
    
         
            +
            				Readline::HISTORY.push(cmd)
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            				execute(cmd)
         
     | 
| 
      
 60 
     | 
    
         
            +
            			end
         
     | 
| 
      
 61 
     | 
    
         
            +
            		end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            		# Save history to ~/.rush/history when the shell exists.
         
     | 
| 
      
 64 
     | 
    
         
            +
            		def finish
         
     | 
| 
      
 65 
     | 
    
         
            +
            			@config.save_history(Readline::HISTORY.to_a)
         
     | 
| 
      
 66 
     | 
    
         
            +
            			puts
         
     | 
| 
      
 67 
     | 
    
         
            +
            			exit
         
     | 
| 
      
 68 
     | 
    
         
            +
            		end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            		# Nice printing of different return types, particularly Rush::SearchResults.
         
     | 
| 
      
 71 
     | 
    
         
            +
            		def print_result(res)
         
     | 
| 
      
 72 
     | 
    
         
            +
            			return if self.suppress_output
         
     | 
| 
      
 73 
     | 
    
         
            +
            			if res.kind_of? String
         
     | 
| 
      
 74 
     | 
    
         
            +
            				puts res
         
     | 
| 
      
 75 
     | 
    
         
            +
            			elsif res.kind_of? Rush::SearchResults
         
     | 
| 
      
 76 
     | 
    
         
            +
            				widest = res.entries.map { |k| k.full_path.length }.max
         
     | 
| 
      
 77 
     | 
    
         
            +
            				res.entries_with_lines.each do |entry, lines|
         
     | 
| 
      
 78 
     | 
    
         
            +
            					print entry.full_path
         
     | 
| 
      
 79 
     | 
    
         
            +
            					print ' ' * (widest - entry.full_path.length + 2)
         
     | 
| 
      
 80 
     | 
    
         
            +
            					print "=> "
         
     | 
| 
      
 81 
     | 
    
         
            +
            					print res.colorize(lines.first.strip.head(30))
         
     | 
| 
      
 82 
     | 
    
         
            +
            					print "..." if lines.first.strip.length > 30
         
     | 
| 
      
 83 
     | 
    
         
            +
            					if lines.size > 1
         
     | 
| 
      
 84 
     | 
    
         
            +
            						print " (plus #{lines.size - 1} more matches)"
         
     | 
| 
      
 85 
     | 
    
         
            +
            					end
         
     | 
| 
      
 86 
     | 
    
         
            +
            					print "\n"
         
     | 
| 
      
 87 
     | 
    
         
            +
            				end
         
     | 
| 
      
 88 
     | 
    
         
            +
            				puts "#{res.entries.size} matching files with #{res.lines.size} matching lines"
         
     | 
| 
      
 89 
     | 
    
         
            +
            			elsif res.respond_to? :each
         
     | 
| 
      
 90 
     | 
    
         
            +
            				counts = {}
         
     | 
| 
      
 91 
     | 
    
         
            +
            				res.each do |item|
         
     | 
| 
      
 92 
     | 
    
         
            +
            					puts item
         
     | 
| 
      
 93 
     | 
    
         
            +
            					counts[item.class] ||= 0
         
     | 
| 
      
 94 
     | 
    
         
            +
            					counts[item.class] += 1
         
     | 
| 
      
 95 
     | 
    
         
            +
            				end
         
     | 
| 
      
 96 
     | 
    
         
            +
            				if counts == {}
         
     | 
| 
      
 97 
     | 
    
         
            +
            					puts "=> (empty set)"
         
     | 
| 
      
 98 
     | 
    
         
            +
            				else
         
     | 
| 
      
 99 
     | 
    
         
            +
            					count_s = counts.map do |klass, count|
         
     | 
| 
      
 100 
     | 
    
         
            +
            						"#{count} x #{klass}"
         
     | 
| 
      
 101 
     | 
    
         
            +
            					end.join(', ')
         
     | 
| 
      
 102 
     | 
    
         
            +
            					puts "=> #{count_s}"
         
     | 
| 
      
 103 
     | 
    
         
            +
            				end
         
     | 
| 
      
 104 
     | 
    
         
            +
            			else
         
     | 
| 
      
 105 
     | 
    
         
            +
            				puts "=> #{res.inspect}"
         
     | 
| 
      
 106 
     | 
    
         
            +
            			end
         
     | 
| 
      
 107 
     | 
    
         
            +
            		end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
            		def path_parts(input)   # :nodoc:
         
     | 
| 
      
 110 
     | 
    
         
            +
            			input.match(/(\w+(?:\[[^\]]+\])*)\[(['"])([^\]]+)$/)
         
     | 
| 
      
 111 
     | 
    
         
            +
            			$~.to_a.slice(1, 3).push($~.pre_match)
         
     | 
| 
      
 112 
     | 
    
         
            +
            		rescue
         
     | 
| 
      
 113 
     | 
    
         
            +
            			[ nil, nil, nil, nil ]
         
     | 
| 
      
 114 
     | 
    
         
            +
            		end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
            		# Try to do tab completion on dir square brackets accessors.
         
     | 
| 
      
 117 
     | 
    
         
            +
            		#
         
     | 
| 
      
 118 
     | 
    
         
            +
            		# Example:
         
     | 
| 
      
 119 
     | 
    
         
            +
            		#
         
     | 
| 
      
 120 
     | 
    
         
            +
            		# dir['subd    # presing tab here will produce dir['subdir/ if subdir exists
         
     | 
| 
      
 121 
     | 
    
         
            +
            		#
         
     | 
| 
      
 122 
     | 
    
         
            +
            		# This isn't that cool yet, because it can't do multiple levels of subdirs.
         
     | 
| 
      
 123 
     | 
    
         
            +
            		# It does work remotely, though, which is pretty sweet.
         
     | 
| 
      
 124 
     | 
    
         
            +
            		def completion_proc
         
     | 
| 
      
 125 
     | 
    
         
            +
            			proc do |input|
         
     | 
| 
      
 126 
     | 
    
         
            +
            				possible_var, quote, partial_path, pre = path_parts(input)
         
     | 
| 
      
 127 
     | 
    
         
            +
            				if possible_var
         
     | 
| 
      
 128 
     | 
    
         
            +
            					original_var, fixed_path = possible_var, ''
         
     | 
| 
      
 129 
     | 
    
         
            +
            					if /^(.+\/)([^\/]+)$/ === partial_path
         
     | 
| 
      
 130 
     | 
    
         
            +
            						fixed_path, partial_path = $~.captures
         
     | 
| 
      
 131 
     | 
    
         
            +
            						possible_var += "['#{fixed_path}']"
         
     | 
| 
      
 132 
     | 
    
         
            +
            					end
         
     | 
| 
      
 133 
     | 
    
         
            +
            					full_path = eval("#{possible_var}.full_path", @pure_binding) rescue nil
         
     | 
| 
      
 134 
     | 
    
         
            +
            					box = eval("#{possible_var}.box", @pure_binding) rescue nil
         
     | 
| 
      
 135 
     | 
    
         
            +
            					if full_path and box
         
     | 
| 
      
 136 
     | 
    
         
            +
            						dir = Rush::Dir.new(full_path, box)
         
     | 
| 
      
 137 
     | 
    
         
            +
            						return dir.entries.select do |e|
         
     | 
| 
      
 138 
     | 
    
         
            +
            							e.name.match(/^#{Regexp.escape(partial_path)}/)
         
     | 
| 
      
 139 
     | 
    
         
            +
            						end.map do |e|
         
     | 
| 
      
 140 
     | 
    
         
            +
            							(pre || '') + original_var + '[' + quote + fixed_path + e.name + (e.dir? ? "/" : "")
         
     | 
| 
      
 141 
     | 
    
         
            +
            						end
         
     | 
| 
      
 142 
     | 
    
         
            +
            					end
         
     | 
| 
      
 143 
     | 
    
         
            +
            				end
         
     | 
| 
      
 144 
     | 
    
         
            +
            				nil
         
     | 
| 
      
 145 
     | 
    
         
            +
            			end
         
     | 
| 
      
 146 
     | 
    
         
            +
            		end
         
     | 
| 
      
 147 
     | 
    
         
            +
            	end
         
     | 
| 
      
 148 
     | 
    
         
            +
            end
         
     |