elasticshell 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/README.rdoc +119 -55
  2. data/VERSION +1 -1
  3. data/bin/es +0 -2
  4. data/lib/elasticshell.rb +30 -25
  5. data/lib/elasticshell/client.rb +34 -13
  6. data/lib/elasticshell/command.rb +14 -170
  7. data/lib/elasticshell/commands/blank.rb +14 -0
  8. data/lib/elasticshell/commands/cd.rb +27 -0
  9. data/lib/elasticshell/commands/connect.rb +31 -0
  10. data/lib/elasticshell/commands/df.rb +23 -0
  11. data/lib/elasticshell/commands/help.rb +77 -0
  12. data/lib/elasticshell/commands/ls.rb +66 -0
  13. data/lib/elasticshell/commands/pretty.rb +21 -0
  14. data/lib/elasticshell/commands/pwd.rb +17 -0
  15. data/lib/elasticshell/commands/request.rb +81 -0
  16. data/lib/elasticshell/commands/request_parser.rb +77 -0
  17. data/lib/elasticshell/commands/set_verb.rb +23 -0
  18. data/lib/elasticshell/commands/unknown.rb +17 -0
  19. data/lib/elasticshell/scopes.rb +81 -50
  20. data/lib/elasticshell/scopes/cluster.rb +8 -16
  21. data/lib/elasticshell/scopes/global.rb +22 -23
  22. data/lib/elasticshell/scopes/index.rb +35 -29
  23. data/lib/elasticshell/scopes/mapping.rb +8 -28
  24. data/lib/elasticshell/scopes/nodes.rb +6 -15
  25. data/lib/elasticshell/shell.rb +155 -93
  26. data/lib/elasticshell/utils.rb +10 -0
  27. data/lib/elasticshell/{error.rb → utils/error.rb} +1 -0
  28. data/lib/elasticshell/utils/has_name.rb +14 -0
  29. data/lib/elasticshell/utils/has_verb.rb +15 -0
  30. data/lib/elasticshell/{log.rb → utils/log.rb} +1 -1
  31. data/lib/elasticshell/utils/recognizes_verb.rb +25 -0
  32. data/spec/elasticshell/client_spec.rb +55 -0
  33. data/spec/elasticshell/commands/blank_spec.rb +14 -0
  34. data/spec/elasticshell/commands/cd_spec.rb +23 -0
  35. data/spec/elasticshell/commands/connect_spec.rb +21 -0
  36. data/spec/elasticshell/commands/df_spec.rb +18 -0
  37. data/spec/elasticshell/commands/help_spec.rb +21 -0
  38. data/spec/elasticshell/commands/ls_spec.rb +24 -0
  39. data/spec/elasticshell/commands/pretty_spec.rb +19 -0
  40. data/spec/elasticshell/commands/pwd_spec.rb +14 -0
  41. data/spec/elasticshell/commands/request_parser_spec.rb +4 -0
  42. data/spec/elasticshell/commands/request_spec.rb +60 -0
  43. data/spec/elasticshell/commands/set_verb_spec.rb +14 -0
  44. data/spec/elasticshell/scopes_spec.rb +79 -0
  45. data/spec/elasticshell/shell_spec.rb +19 -0
  46. data/spec/elasticshell/utils/has_name_spec.rb +15 -0
  47. data/spec/elasticshell/utils/has_verb_spec.rb +24 -0
  48. data/spec/elasticshell/utils/recognizes_verb_spec.rb +23 -0
  49. data/spec/spec_helper.rb +4 -5
  50. data/spec/support/data.yml +45 -0
  51. data/spec/support/fake_output.rb +27 -0
  52. metadata +73 -4
data/README.rdoc CHANGED
@@ -26,12 +26,12 @@ How about
26
26
 
27
27
  == Installation
28
28
 
29
- Installing Elasticshell should be as simple as installing the gem:
29
+ Install the gem:
30
30
 
31
31
  $ sudo gem install elasticshell
32
32
 
33
- This should install a binary program 'es' that you can run from the
34
- command line to start Elasticshell. Try
33
+ which installs a program 'es' that you can run from the command line
34
+ to start Elasticshell. Try
35
35
 
36
36
  $ es --help
37
37
 
@@ -53,57 +53,115 @@ Within Elasticshell, there are three variables whose values affect
53
53
  behavior. These variables are reflected in the default prompt, for
54
54
  example:
55
55
 
56
- GET /my_index/my_type >
56
+ GET /my_index/my_type$
57
57
 
58
58
  This prompt tells us three things:
59
59
 
60
60
  1. The default HTTP verb we're using for requests is +GET+.
61
61
 
62
- 2. The default API "scope" we're in is <tt>/my_index/my_type</tt>.
62
+ 2. The default API "scope" we're in is <tt>/my_index/my_type</tt>. If the shell is connected to an Elasticsearch server and the scope exists, it will be colored green. Otherwise it's yellow.
63
63
 
64
- 3. Elasticshell will print raw responses from the database -- this is the <tt>></tt> at the end of the prompt. If we were in pretty-print mode, this would become a <tt>$</tt>.
64
+ 3. Elasticshell will print raw responses from the database -- this is the <tt>$</tt> at the end of the prompt. If we were in pretty-print mode, this would become a <tt>$$</tt>.
65
65
 
66
- === Changing Scope
66
+ === Connecting to the Database
67
+
68
+ Elasticshell will try to connect to the Elasticsearch hosts passed
69
+ with the <tt>--servers</tt> option during startup. At any other time,
70
+ you can connect to servers by issuing the +connect+ command:
71
+
72
+ GET /$ connect http://192.168.1.10:9200 http://192.168.1.11:9200 http://192.168.1.12:9200 http://192.168.1.13:9200
73
+
74
+ === Understanding Scope
75
+
76
+ Scopes are defined by the Elasticsearch REST API. Some scopes like
77
+ <tt>/_cluster</tt> or <tt>/nodes</tt> are static and present for all
78
+ Elasticsearch clusters. Other scopes like <tt>/my_index/my_type</tt>
79
+ depend upon the particular cluster.
67
80
 
68
81
  Use the +cd+ built-in to move between scopes:
69
82
 
70
- GET /my_index/my_type > cd /other_index/other_type
71
- GET /other_index/other_type > cd ..
72
- GET /other_index > cd
73
- GET / >
83
+ GET /$ cd /blog/comments
84
+ GET /blog/comments$ cd ..
85
+ GET /blog$ cd /blog/entries
86
+ GET /blog/entries$ cd
87
+ GET /$
88
+
89
+ ==== Different kinds of scopes
90
+
91
+ The +ls+ command will show the contents of a given scope:
92
+
93
+ GET /$ ls
94
+ blog _cluster _nodes _status
95
+
96
+ but the +ll+ command gives more output:
97
+
98
+ GET /$ ll
99
+ i 1/1/0 5 3.3kb blog
100
+ s _cluster
101
+ s _nodes
102
+ - _status
74
103
 
75
- Tab-complete within a scope after typing +cd+ to see what other scopes
76
- live under this one.
104
+ Here you see that +blog+
105
+
106
+ - is an index (the +i+ in the first column)
107
+ - has 1 total shard, 1 successful shard, and 0 failed shards
108
+ - has 5 documents
109
+ - occupies 3.3kb of space on disk
110
+
111
+ And, because of the +s+ in the first-column, +_cluster+ and +_nodes+
112
+ are scopes -- you can +cd+ into them.
113
+
114
+ Finally, +_status+ is a request, you can't +cd+ into it, but you can
115
+ issue it.
116
+
117
+ If you were to first +cd+ into the index and run +ll+ you'll see
118
+ different output:
119
+
120
+ GET /$ cd /blog/
121
+ GET /blog$ ll
122
+ m comments
123
+ m entries
124
+ - _aliases
125
+ - _search
126
+ - _stats
127
+ - _status
128
+
129
+ +_aliases+ and so on are just more requests you can make but
130
+ +comments+ and +entries+ are mappings (they have an +m+ in the
131
+ first-column).
77
132
 
78
133
  === Changing HTTP Verb
79
134
 
80
135
  You can change Elasticsearch's default HTTP verb by giving it one.
81
136
  Here's the same thing in two steps:
82
137
 
83
- GET / > PUT
84
- PUT / > /my_new_index
138
+ GET /$ PUT
139
+ PUT /$ /my_new_index
140
+
141
+ You can also do this on a per-request basis
85
142
 
86
- Non-ambiguous shortcuts for HTTP verbs will also work, e.g. - +pu+ in
87
- this case for +PUT+.
143
+ GET /$ PUT /my_new_index
144
+ GET /$
88
145
 
89
146
  === Changing Prettiness
90
147
 
91
148
  Typing +pretty+ at any time will toggle Elasticsearch's
92
149
  pretty-printing format on or off.
93
150
 
94
- GET / > pretty
95
- GET / $
151
+ GET /$ pretty
152
+ GET /$$
96
153
 
97
- The <tt>$</tt>-sign means it's pretty...
154
+ The extra <tt>$</tt>-sign means it's pretty...
98
155
 
99
- === Running Commands
156
+ == Making Requests
100
157
 
101
- There are a lot of different ways of telling Elasticsearch what you
102
- want done.
158
+ Scopes are fine for organizing the API but to get anything done you'll
159
+ have to send a request.
103
160
 
104
- ==== Named commands
161
+ === Named requests
105
162
 
106
- Each scope has different commands, as per the {Elasticsearch API
163
+ Each scope has different fixed, named requests, as per the
164
+ {Elasticsearch API
107
165
  documentation}[http://www.elasticsearch.org/guide/reference/api/].
108
166
  Within a scope, tab-complete on the first word to see a list of
109
167
  possible commands. Hit enter after a command to see output from
@@ -111,28 +169,32 @@ Elasticsearch.
111
169
 
112
170
  Here's a command to get the status for the cluster:
113
171
 
114
- GET / > _status
172
+ GET /$ _status
115
173
 
116
174
  Here's a command to get the health of the cluster:
117
175
 
118
- GET / > cd _cluster
119
- GET /_cluster > health
176
+ GET /$ cd _cluster
177
+ GET /_cluster$ health
178
+
179
+ which you could also have issued like this
180
+
181
+ GET /$ _cluster/health
120
182
 
121
- ==== Commands with query strings
183
+ === Using query strings
122
184
 
123
185
  Commands will also accept a query string, as in this example of a
124
186
  search through +my_index+:
125
187
 
126
- GET /my_index > _search?q=foo+AND+bar
188
+ GET /my_index$ _search?q=foo+AND+bar
127
189
 
128
- ==== Commands with query bodies
190
+ === Using a body
129
191
 
130
- In this example the query <tt>foo AND bar</tt> was passed via the
192
+ In the above example the query <tt>foo AND bar</tt> was passed via the
131
193
  query string part of a URL. Passing a more complex query requires we
132
194
  put the query in the body of the request. If you're willing to forego
133
195
  using spaces you can do this right on the same line:
134
196
 
135
- GET /my_index > _search {"query":{"query_string":{"query":"foo"}}}
197
+ GET /my_index$ _search {"query":{"query_string":{"query":"foo"}}}
136
198
 
137
199
  But if you want more expressiveness you can either name a file (with
138
200
  tab-completion) that contains the body you want:
@@ -148,12 +210,12 @@ tab-completion) that contains the body you want:
148
210
 
149
211
  followed by
150
212
 
151
- GET /my_index > _search /tmp/query.json
213
+ GET /my_index$ _search /tmp/query.json
152
214
 
153
215
  Or you can do +cat+-style, pasting the query into the shell, by using
154
216
  the <tt>-</tt> character:
155
217
 
156
- GET /my_index > _search -
218
+ GET /my_index$ _search -
157
219
  {
158
220
  "query": {
159
221
  "query_string: {
@@ -165,38 +227,40 @@ the <tt>-</tt> character:
165
227
  Don't forget to use <tt>Ctrl-D</tt> to send an +EOF+ to flush the
166
228
  input of the query.
167
229
 
168
- ==== Arbitrary commands
230
+ === Redirecting output
169
231
 
170
- You can send an arbitrary HTTP request to Elasticsearch, just spell
171
- the command with a leading slash:
232
+ You can redirect the output from a request in a variety of ways.
172
233
 
173
- GET / > /my_index/_search?q=foo+AND+bar
234
+ Most simply is to redirect to a file:
174
235
 
175
- You can specify a different HTTP verb by prefixing it before the path
176
- you send the request to. Here's how to create an index using a +PUT+
177
- request:
236
+ GET /my_index$ _search /tmp/query_with_lots_of_output.json > /data/output_file.json
178
237
 
179
- GET / > PUT /my_new_index
238
+ Or you can try sending it to Ruby itself:
180
239
 
181
- You can also change Elasticsearch's default HTTP verb by giving it
182
- one. Here's the same thing in two steps:
240
+ GET /my_index$ _search /tmp/query_that_needs_filtering.json | puts response["hits"]["hits"].first["body"]
183
241
 
184
- GET / > PUT
185
- PUT / > /my_new_index
242
+ Everything to the right of the +|+ is executing within a Ruby process
243
+ that has the +response+ and +request+ variables in scope. You can be
244
+ even more free by just piping without any Ruby code, which will leave
245
+ you in a Ruby (Pry) shell with the same binding.
186
246
 
187
- Non-ambiguous shortcuts for HTTP verbs will also work, e.g. - +pu+ in
188
- this case for +PUT+.
247
+ GET /my_index$ _search /tmp/query_that_needs_interaction.json |
248
+ >> response
249
+ => {"took"=>1, "timed_out"=>false, ... }
250
+ >> request
251
+ => {:verb=>"GET", :path=>"/_search", :query_options=>{}, :body=>""}
189
252
 
190
- === Running just a single command
253
+ === Requests from the command line
191
254
 
192
255
  Instead of running Elasticshell interactively, you can exit after
193
- running only a single command by using the <tt>--only</tt> option on
194
- startup. For example,
256
+ running only a single command by feeding the request path directly to
257
+ the +es+ script. For example
195
258
 
196
- $ es --only /_cluster/health
259
+ $ es /_cluster/health
260
+ $ es --scope=/_cluster health
261
+ $ es --verb=GET /_cluster/health
197
262
 
198
- will output the cluster health and exit immediately. This can be
199
- combined with the <tt>--pretty</tt> option for readability.
263
+ all work like you think they do.
200
264
 
201
265
  The <tt>--only</tt> option can also be passed a <tt>.</tt>-separated
202
266
  hierarchical list of keys to slice into the resulting object. This is
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.4
data/bin/es CHANGED
@@ -1,6 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $: << File.expand_path('../../lib', __FILE__) unless $:.include?($: << File.expand_path('../../lib', __FILE__))
4
3
  require 'elasticshell'
5
-
6
4
  Elasticshell.start
data/lib/elasticshell.rb CHANGED
@@ -2,58 +2,63 @@ require 'rubygems'
2
2
  require 'json'
3
3
  require 'configliere'
4
4
 
5
- require 'elasticshell/shell'
6
- require 'elasticshell/scopes'
7
- require 'elasticshell/client'
5
+ require 'elasticshell/utils'
8
6
 
9
7
  Settings.use(:commandline)
10
8
 
11
- Settings.define(:servers, :description => "A comma-separated list of Elasticsearch servers to connect to.", :type => Array, :default => Elasticshell::Client::DEFAULT_SERVERS)
9
+ Settings.define(:servers, :description => "A comma-separated list of Elasticsearch servers to connect to.", :type => Array, :default => 'http://localhost:9200')
12
10
  Settings.define(:only, :description => "A dot-separated hierarchical key to extract from the output scope.")
13
11
  Settings.define(:pretty, :description => "Pretty-print all output. ", :default => false, :type => :boolean)
14
12
  Settings.define(:verb, :description => "Set the default HTTP verb. ", :default => "GET")
15
13
  Settings.define(:version, :description => "Print Elasticshell version and exit. ", :default => false, :type => :boolean)
14
+ Settings.define(:scope, :description => "The default scope to start the shell in.", :default => "/")
16
15
  Settings.description = <<-DESC
17
16
  Elasticshell is a command-line shell for interacting with an
18
17
  Elasticsearch database. It has the following start-up options.
19
18
  DESC
20
19
 
21
20
  def Settings.usage
22
- "usage: #{File.basename($0)} [OPTIONS] [SCOPE]"
21
+ "usage: #{File.basename($0)} [OPTIONS] [REQUEST]"
23
22
  end
24
23
  Settings.resolve!
25
24
 
26
25
  module Elasticshell
27
26
 
27
+ autoload :Client, 'elasticshell/client'
28
+ autoload :Shell, 'elasticshell/shell'
29
+ autoload :Scope, 'elasticshell/scopes'
30
+ autoload :Scopes, 'elasticshell/scopes'
31
+ autoload :Command, 'elasticshell/command'
32
+ autoload :Commands, 'elasticshell/command'
33
+
28
34
  def self.version
29
35
  @version ||= begin
30
- File.read(File.expand_path('../../VERSION', __FILE__)).chomp
31
- rescue => e
32
- 'unknown'
33
- end
36
+ File.read(File.expand_path('../../VERSION', __FILE__)).chomp
37
+ rescue => e
38
+ 'unknown'
39
+ end
34
40
  end
35
41
 
36
42
  def self.start *args
37
- if Settings[:version]
38
- puts version
39
- exit()
40
- end
41
-
42
- es = Shell.new(Settings)
43
- if Settings[:only]
44
- if Settings.rest.length == 0
45
- $stderr.puts "Starting with the --only option requires the first argument to name an API path (like `/_cluster/health')"
43
+ begin
44
+ case
45
+ when Settings[:version]
46
+ puts version
47
+ exit()
48
+ when Settings[:only] && Settings.rest.empty?
49
+ raise ArgumentError.new("Starting with the --only option requires a request argument (like `/_cluster/health')")
46
50
  exit(1)
47
- else
51
+ when (! Settings.rest.empty?)
52
+ es = Shell.new(Settings.merge(:log_requests => false))
53
+ es.connect
48
54
  es.eval_line(Settings.rest.first)
49
55
  exit()
56
+ else
57
+ Shell.new(Settings).run
50
58
  end
51
- else
52
- if Settings.rest.length > 0
53
- es.scope = Scopes.from_path(Settings.rest.first, :client => es.client)
54
- end
55
- es.run
59
+ rescue Elasticshell::Error => e
60
+ $stderr.puts e.message
61
+ exit(2)
56
62
  end
57
63
  end
58
-
59
64
  end
@@ -1,23 +1,36 @@
1
1
  require 'rubberband'
2
- require 'elasticshell/error'
3
- require 'elasticshell/log'
4
2
 
5
3
  module Elasticshell
6
4
 
7
5
  class Client
8
6
 
9
- DEFAULT_SERVERS = ['http://localhost:9200']
10
-
11
7
  def initialize options={}
12
- @client ||= ::ElasticSearch::Client.new(options[:servers] || DEFAULT_SERVERS)
8
+ @options = options
9
+ end
10
+
11
+ def connect options={}
12
+ servers = (options.merge(@options)[:servers] || Settings[:servers].to_s.split(","))
13
+ begin
14
+ @client = ElasticSearch::Client.new(servers)
15
+ rescue ElasticSearch::ConnectionFailed => e
16
+ raise ClientError.new("Could not connect to Elasticsearch server(s) at #{servers.join(',')}")
17
+ end
18
+ end
19
+
20
+ def connected?
21
+ @client
13
22
  end
14
23
 
15
24
  def request verb, params={}, options={}, body=''
25
+ raise ClientError.new("Not connected to any Elasticsearch servers.") unless connected?
16
26
  safe = options.delete(:safely)
17
27
  safe_return = options.delete(:return)
18
- # log_request(verb, params, options)
28
+
29
+ # Log by default
30
+ log_request(verb, params, options) unless options.delete(:log) == false
31
+
19
32
  begin
20
- @client.execute(:standard_request, verb, params, options, body)
33
+ perform_request(verb, params, options, body)
21
34
  rescue ElasticSearch::RequestError, ArgumentError => e
22
35
  if safe
23
36
  safe_return
@@ -27,13 +40,21 @@ module Elasticshell
27
40
  end
28
41
  end
29
42
 
43
+ def perform_request verb, params, options, body
44
+ @client.execute(:standard_request, verb.downcase.to_sym, params, options, body)
45
+ end
46
+
30
47
  def log_request verb, params, options={}
31
- # FIXME digging way too deep into rubberband here...is it really
32
- # necessary?
33
- uri = @client.instance_variable_get('@connection').send(:generate_uri, params)
34
- query = @client.instance_variable_get('@connection').send(:generate_query_string, options)
35
- path = [uri, query].reject { |s| s.nil? || s.strip.empty? }.join("?")
36
- Elasticshell.log("#{verb.to_s.upcase} #{path}")
48
+ begin
49
+ # FIXME digging way too deep into rubberband here...is it really
50
+ # necessary?
51
+ uri = @client.instance_variable_get('@connection').send(:generate_uri, params)
52
+ query = @client.instance_variable_get('@connection').send(:generate_query_string, options)
53
+ path = [uri, query].reject { |s| s.nil? || s.strip.empty? }.join("?").gsub(Regexp.new("^/+"), "/")
54
+ Elasticshell.log("#{verb.to_s.upcase} #{path}".strip)
55
+ rescue
56
+ Elasticshell.log("#{verb.to_s.upcase} #{params.inspect} #{options.inspect}".strip)
57
+ end
37
58
  end
38
59
 
39
60
  def safely verb, params={}, options={}, body=''
@@ -1,12 +1,7 @@
1
- require 'elasticshell/error'
2
- require 'uri'
3
-
4
1
  module Elasticshell
5
2
 
6
3
  class Command
7
4
 
8
- HTTP_VERB_RE = "(?:G(?:ET?)?|PO(?:ST?)?|PUT?|D(?:E(?:L(?:E(?:TE?)?)?)?)?)"
9
-
10
5
  attr_accessor :shell, :input
11
6
 
12
7
  def initialize shell, input
@@ -14,178 +9,27 @@ module Elasticshell
14
9
  self.input = input
15
10
  end
16
11
 
17
- def evaluate!
18
- case
19
- when setting_scope? then set_scope!
20
- when setting_http_verb? then set_http_verb!
21
- when making_explicit_req? then make_explicit_req!
22
- when pretty? then pretty!
23
- when help? then help!
24
- when ls? then ls!
25
- when blank? then nil
26
- when scope_command? then run_scope_command!
27
- else
28
- raise ArgumentError.new("Unknown command '#{input}' for scope '#{shell.scope.path}'. Try typing 'help' for a list of available commands.")
29
- end
30
- end
31
-
32
- def setting_scope?
33
- input =~ /^cd/
34
- end
35
-
36
- def set_scope!
37
- if input =~ /^cd$/
38
- shell.scope = Scopes.global(:client => shell.client)
39
- return
40
- end
41
-
42
- return unless input =~ /^cd\s+(.+)$/
43
- scope = $1
44
- if scope =~ %r!^/!
45
- shell.scope = Scopes.from_path(scope, :client => shell.client)
46
- else
47
- shell.scope = Scopes.from_path(File.expand_path(File.join(shell.scope.path, scope)), :client => shell.client)
48
- end
49
- end
50
-
51
- def setting_http_verb?
52
- input =~ Regexp.new("^" + HTTP_VERB_RE + "$", true)
53
- end
54
-
55
- def canonicalize_http_verb v
56
- case v
57
- when /^G/i then "GET"
58
- when /^PO/i then "POST"
59
- when /^PU/i then "PUT"
60
- when /^D/i then "DELETE"
61
- end
62
- end
63
-
64
- def set_http_verb!
65
- shell.verb = canonicalize_http_verb(input)
66
- end
67
-
68
- def scope_command?
69
- shell.scope.command?(input)
70
- end
71
-
72
- def run_scope_command!
73
- shell.scope.execute(input, shell)
74
- end
75
-
76
- def blank?
77
- input.empty?
78
- end
79
-
80
- def help?
81
- input =~ /^help/i
82
- end
83
-
84
- def help!
85
- shell.scope.refresh
86
- shell.print <<HELP
87
-
88
- Globally available commands:
89
-
90
- cd [PATH]
91
- Change scope to the given path. Current path is reflected in the
92
- prompt (it's '#{shell.scope.path}' right now).
93
-
94
- Ex:
95
- GET / > cd /my_index
96
- GET /my_index > cd /other_index/some_type
97
- GET /other_index/some_type
98
-
99
- [get|post|put|delete]
100
- Set the default HTTP verb (can use a non-ambiguous shortcut like 'g'
101
- for 'GET' or 'pu' for 'PUT'). Current default HTTP verb is '#{shell.verb}'.
102
-
103
- ls
104
- Show what indices or mappings are within the current scope.
105
-
106
- help
107
- Show contextual help.
108
-
109
- [VERB] PATH
110
- Send an HTTP request with the given VERB to the given PATH
111
- (including query string if given). If no verb is given, use the
112
- default.
113
-
114
- Ex: Simple search
115
- GET / > /my_index/_search?q=query+string
116
- {...}
117
-
118
- Ex: Create an index
119
- GET / > PUT /my_new_index
120
- {...}
121
-
122
- or
123
-
124
- GET / > put
125
- PUT / > /my_new_index
126
- {...}
127
-
128
- #{shell.scope.help}
129
- HELP
12
+ def self.matches? input
13
+ raise NotImplementedError.new("Define the 'matches?' method on #{self.class}")
130
14
  end
131
15
 
132
- def ls?
133
- input =~ /^l(s|l|a)?$/i
16
+ def be_connected!
17
+ raise ClientError.new("Not connected to any Elasticsearch servers.") unless shell.connected?
134
18
  end
135
19
 
136
- def ls!
137
- shell.scope.refresh!
138
- case
139
- when input =~ /ll/
140
- shell.print shell.scope.contents.join("\n")
141
- else
142
- shell.print shell.scope.contents.join(' ')
143
- end
144
- end
145
-
146
- def pretty?
147
- input =~ /pretty/i
148
- end
149
-
150
- def pretty!
151
- if shell.pretty?
152
- shell.not_pretty!
153
- else
154
- shell.pretty!
155
- end
156
- end
157
-
158
- def making_explicit_req?
159
- input =~ Regexp.new("^(" + HTTP_VERB_RE + "\s+)?/", true)
20
+ def evaluate!
21
+ raise NotImplementedError.new("Define the 'evaluate!' instance method in your subclass of #{self.class}")
160
22
  end
23
+ end
161
24
 
162
- def make_explicit_req!
163
- if input =~ Regexp.new("^(" + HTTP_VERB_RE + ")\s+(.+)$", true)
164
- verb, path_and_query = canonicalize_http_verb($1), $2
165
- else
166
- verb, path_and_query = shell.verb, input
167
- end
168
- path, query = path_and_query.split('?')
169
-
170
- params = {}
171
- keys = [:index, :type, :id, :op]
172
- parts = path.gsub(%r!^/!,'').gsub(%r!/$!,'').split('/')
173
- while parts.size > 0
174
- part = parts.shift
175
- key = (keys.shift or ArgumentError.new("The input '#{path}' has too many path components."))
176
- params[key] = part
177
- end
178
-
179
- options = {}
180
- URI.decode_www_form(query || '').each do |key, value|
181
- options[key] = value
25
+ module Commands
26
+ PRIORITY = [].tap do |priority|
27
+ %w[cd pwd df connect help ls pretty set_verb blank request unknown].each do |command_name|
28
+ klass_name = command_name.split("_").map(&:capitalize).join("")
29
+ autoload klass_name.to_sym, "elasticshell/commands/#{command_name}"
30
+ priority << klass_name
182
31
  end
183
-
184
- shell.print(shell.client.request(verb.downcase.to_sym, params, options))
185
32
  end
186
-
187
-
188
33
  end
189
-
190
- end
191
34
 
35
+ end