desi 0.1.0 → 0.2.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.
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Guardfile CHANGED
@@ -3,3 +3,9 @@
3
3
  guard 'yard' do
4
4
  watch(%r{lib/.+\.rb})
5
5
  end
6
+
7
+ guard 'rspec' do
8
+ watch(%r{^spec/.+_spec\.rb$})
9
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
10
+ watch('spec/spec_helper.rb') { "spec" }
11
+ end
data/README.md CHANGED
@@ -13,7 +13,7 @@ It can:
13
13
  It can be used both as a command-line tool and as a library.
14
14
 
15
15
 
16
- ## Usage
16
+ ## Usage (command-line)
17
17
 
18
18
  $ desi list # List locally installed ElasticSearch releases
19
19
  $ desi releases # List all upstream Elastic Search releases (latest 5 by default)
@@ -25,14 +25,14 @@ It can be used both as a command-line tool and as a library.
25
25
 
26
26
  $ desi indices "^foo" # List all indices whose name match /^foo/
27
27
  $ desi indices "^foo" --delete # Delete all matching indices
28
- $ desi indices "bar$" --empty # Remove all records from the matching
29
- # indices
28
+ $ desi indices "bar$" --empty # Remove all records from the matching indices
30
29
 
31
- ## Examples
30
+ ## Examples (command-line and Ruby)
32
31
 
33
- ### Currently installed releases
32
+ ### Get the list of locally installed releases
34
33
 
35
- The current version is the one symlinked to `$HOME/elasticsearch/current`
34
+ The current version is the one symlinked to `$HOME/elasticsearch/current`, that
35
+ will be spun up by (`desi start`)
36
36
 
37
37
  * command-line
38
38
 
@@ -52,6 +52,54 @@ The current version is the one symlinked to `$HOME/elasticsearch/current`
52
52
  ```
53
53
 
54
54
 
55
+ ### List and delete some indices
56
+
57
+ * command-line
58
+
59
+ ```shell
60
+ $ # List all local indices
61
+ $ desi indices
62
+ Indices from host http://127.0.0.1:9200 matching the pattern /.*/
63
+
64
+ foo
65
+ bar
66
+ baz
67
+
68
+ $ # List all indices on remote cluster 129.168.1.42, reachable on port 9800
69
+ $ desi indices --host 129.168.1.42:9800 foo
70
+ Indices from host http://192.168.1.42:9800 matching the pattern /foo/
71
+
72
+ remotefoo1
73
+ remotefoo2
74
+
75
+ $ # Remove all indices whose name starts with "ba"
76
+ $ desi indices --delete "^ba"
77
+ The following indices from host http://127.0.0.1:9200 are now deleted
78
+ * bar
79
+ * baz
80
+ ```
81
+
82
+
83
+ * library
84
+
85
+ ```ruby
86
+ # All local indices
87
+ Desi::IndexManager.new.list #=> ["foo", "bar", "baz"]
88
+
89
+ # All local indices whose name starts with `b`
90
+ Desi::IndexManager.new.list("^b") #=> ["bar", "baz"]
91
+
92
+ # All indices from distant cluster
93
+ Desi::IndexManager.new(host: "192.168.1.42:9800").list #=> ["remotefoo1", "remotefoo2"]
94
+
95
+ # Delete all local indices whose name starts with `ba`
96
+ Desi::IndexManager.new.delete!("^ba") #=> nil
97
+
98
+ # The indices actually disappeared
99
+ Desi::IndexManager.new.list #=> ["foo"]
100
+ ```
101
+
102
+
55
103
 
56
104
  ## Installation
57
105
 
@@ -69,7 +117,7 @@ Or install it yourself as:
69
117
 
70
118
  ## TODO
71
119
 
72
- * add tests, dammit!
120
+ * add more tests
73
121
 
74
122
  * `desi upgrade` (Upgrade to latest version and migrate data)
75
123
  * `desi switch VERSION` (Switch currently active ES version to VERSION)
data/desi.gemspec CHANGED
@@ -15,6 +15,9 @@ an Elastic Search local install for development purposes.}
15
15
  gem.add_dependency "cocaine"
16
16
  gem.add_dependency "addressable"
17
17
 
18
+ gem.add_development_dependency "rake"
19
+ gem.add_development_dependency "rspec"
20
+ gem.add_development_dependency "guard-rspec"
18
21
  gem.add_development_dependency "guard-yard"
19
22
  gem.add_development_dependency "redcarpet"
20
23
  gem.add_development_dependency "rb-inotify"
@@ -11,7 +11,7 @@ module Desi
11
11
  def initialize(opts = {})
12
12
  @destination_dir = Pathname(opts.fetch(:destination_dir, Desi::LocalInstall.new))
13
13
  @host = URI(opts.fetch(:host, 'http://cloud.github.com/'))
14
- @client = Desi::HttpClient.new(@host)
14
+ @client = opts.fetch(:http_client_factory, Desi::HttpClient).new(@host)
15
15
  @verbose = opts[:verbose]
16
16
  end
17
17
 
@@ -8,8 +8,6 @@ module Desi
8
8
 
9
9
  class HttpClient
10
10
 
11
- attr_reader :uri
12
-
13
11
  def initialize(host_string)
14
12
  @uri = to_uri(host_string)
15
13
 
@@ -10,19 +10,24 @@ module Desi
10
10
 
11
11
  # Initializes a Desi::IndexManager instance
12
12
  #
13
- # @param [#to_hash] opts Hash of extra opts
14
- # @option opts [#to_s] :host Host to manage indices for
15
- # (default: 'http://127.0.0.1:9200')
16
- # @option opts [Boolean] :verbose Whether to output the actions' result
17
- # on STDOUT
13
+ # @param [#to_hash] opts Hash of extra opts
18
14
  #
15
+ # @option opts [#to_s] :host ('http://127.0.0.1:9200') Host to manage indices for
16
+ # @option opts [Boolean] :verbose (nil) Whether to output the actions' result
17
+ # on STDOUT
18
+ # @option opts [#new] :http_client_factory (Desi::HttpClient) HTTP transport class
19
+ # to use
20
+ #
21
+ # @note The +:http_client_factory+ should return an instance that responds
22
+ # to #get and #delete
19
23
  # @return [undefined]
20
24
  #
21
25
  # @api public
22
26
  def initialize(opts = {})
23
27
  @host = opts.fetch(:host, 'http://127.0.0.1:9200')
24
28
  @verbose = opts[:verbose]
25
- @client = Desi::HttpClient.new(@host)
29
+ @outputter = opts.fetch(:outputter, Kernel)
30
+ @client = opts.fetch(:http_client_factory, Desi::HttpClient).new(@host)
26
31
  end
27
32
 
28
33
 
@@ -32,8 +37,8 @@ module Desi
32
37
  # pattern being +/.*/+, all releases will be returned if you do not
33
38
  # specify anything.)
34
39
  #
35
- # @param [#to_s] pattern Regexp pattern used to restrict the selection
36
- # @return [Array<String>] List of index names of the ES cluster
40
+ # @param [#to_s] pattern ('.*') Regexp pattern used to restrict the selection
41
+ # @return [Array<String>] List of index names of the ES cluster
37
42
  #
38
43
  # @note This method will also output its result on STDOUT if +@verbose+ is
39
44
  # true
@@ -45,10 +50,10 @@ module Desi
45
50
  def list(pattern = '.*')
46
51
  pattern = Regexp.new(pattern || '.*')
47
52
 
48
- puts "Indices from host #{@client.uri} matching the pattern #{pattern.inspect}\n\n" if @verbose
53
+ @outputter.puts "Indices from host #{@host} matching the pattern #{pattern.inspect}\n\n" if @verbose
49
54
 
50
55
  list = indices(pattern).sort
51
- list.each {|i| puts i } if @verbose
56
+ list.each {|i| @outputter.puts i } if @verbose
52
57
  list
53
58
  end
54
59
 
@@ -69,11 +74,11 @@ module Desi
69
74
  def delete!(pattern)
70
75
  warn "You must provide a pattern" and exit if pattern.nil?
71
76
 
72
- puts "The following indices from host #{@client.uri} are now deleted" if @verbose
77
+ @outputter.puts "The following indices from host #{@host} are now deleted" if @verbose
73
78
 
74
79
  indices(Regexp.new(pattern)).each do |index|
75
80
  @client.delete(index)
76
- puts " * #{index}" if @verbose
81
+ @outputter.puts " * #{index}" if @verbose
77
82
  end
78
83
  end
79
84
 
@@ -94,11 +99,11 @@ module Desi
94
99
  def empty!(pattern)
95
100
  warn "You must provide a pattern" and exit if pattern.nil?
96
101
 
97
- puts "The following indices from host #{@client.uri} are now emptied" if @verbose
102
+ @outputter.puts "The following indices from host #{@host} are now emptied" if @verbose
98
103
 
99
104
  indices(Regexp.new(pattern)).each do |index|
100
105
  @client.delete("#{index}/_query?q=*")
101
- puts " * #{index}" if @verbose
106
+ @outputter.puts " * #{index}" if @verbose
102
107
  end
103
108
  end
104
109
 
@@ -13,7 +13,7 @@ module Desi
13
13
  @host = opts.fetch(:host, 'http://127.0.0.1:9200')
14
14
  @verbose = opts[:verbose]
15
15
  @local_install = LocalInstall.new
16
- @client = Desi::HttpClient.new(@host)
16
+ @client = opts.fetch(:http_client_factory, Desi::HttpClient).new(@host)
17
17
  end
18
18
 
19
19
  def start
@@ -50,7 +50,7 @@ module Desi
50
50
  if version = running_version
51
51
  msg = "OK. Elastic Search cluster '#{cluster_health.cluster_name}' (v#{version}) is running on #{cluster_health.number_of_nodes} node(s) with status #{cluster_health.status}"
52
52
  else
53
- msg = "KO. No Elastic Search instance was found running on #{@client.uri}"
53
+ msg = "KO. No Elastic Search instance was found running on #{@host}"
54
54
  end
55
55
  puts msg if @verbose
56
56
  msg
data/lib/desi/upstream.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require "desi/http_client"
4
+ require "json"
4
5
 
5
6
  module Desi
6
7
  class Upstream
@@ -11,8 +12,8 @@ module Desi
11
12
  end
12
13
  end
13
14
 
14
- def initialize
15
- @client = Desi::HttpClient.new('https://api.github.com/')
15
+ def initialize(opts = {})
16
+ @client = opts.fetch(:http_client_factory, Desi::HttpClient).new('https://api.github.com/')
16
17
  end
17
18
 
18
19
  def releases
data/lib/desi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Desi
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,134 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+ require "desi/index_manager"
5
+ require "json"
6
+
7
+ describe Desi::IndexManager do
8
+
9
+ subject { described_class.new(http_client_factory: http_client_factory) }
10
+
11
+ let(:http_client_factory) { double(new: http_client) }
12
+ let(:http_client) { double('http_client') }
13
+
14
+ def stub_request(method, path, payload)
15
+ http_client.stub(method).with(path).and_return(
16
+ mock("response", body: JSON.unparse(payload))
17
+ )
18
+ end
19
+
20
+ def stub_indices(*names)
21
+ stub_request(:get, '_status', {"indices" => Hash[Array(names).zip]})
22
+ end
23
+
24
+ before do
25
+ stub_indices('foo', 'bar')
26
+ end
27
+
28
+ describe "#list" do
29
+ context "with no specified pattern" do
30
+ it "returns the names of all indices" do
31
+ subject.list.should == %w[bar foo]
32
+ end
33
+ end
34
+
35
+ context "with a pattern" do
36
+ it "returns the matching indices" do
37
+ subject.list('oo').should == %w[foo]
38
+ end
39
+ end
40
+
41
+ context "when verbose is on" do
42
+ let(:outputter) { double("outputter") }
43
+
44
+ subject do
45
+ described_class.new(
46
+ http_client_factory: http_client_factory,
47
+ outputter: outputter,
48
+ verbose: true)
49
+ end
50
+
51
+ it "also outputs on STDOUT" do
52
+ outputter.should_receive(:puts).at_least(:once)
53
+ subject.list('oo')
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "#delete!" do
59
+ context "when the mandatory pattern is not specified" do
60
+ it "raises an ArgumentError" do
61
+ expect { subject.delete! }.to raise_error(ArgumentError)
62
+ end
63
+ end
64
+
65
+ it "deletes all matching indices" do
66
+ http_client.should_receive(:delete).with("foo")
67
+ http_client.should_not_receive(:delete).with("bar")
68
+
69
+ subject.delete!('f.*')
70
+ end
71
+
72
+ context "when verbose is on" do
73
+ let(:outputter) { double("outputter") }
74
+
75
+ subject do
76
+ described_class.new(
77
+ http_client_factory: http_client_factory,
78
+ outputter: outputter,
79
+ verbose: true)
80
+ end
81
+
82
+ it "also outputs on STDOUT" do
83
+ http_client.stub(:delete)
84
+
85
+ outputter.should_receive(:puts).at_least(:once)
86
+ subject.delete!('f.*')
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "#empty!" do
92
+ context "when the mandatory pattern is not specified" do
93
+ it "raises an ArgumentError" do
94
+ expect { subject.empty! }.to raise_error(ArgumentError)
95
+ end
96
+ end
97
+
98
+ it "deletes all matching indices" do
99
+ http_client.should_receive(:delete).with("foo/_query?q=*")
100
+ http_client.should_not_receive(:delete).with("bar")
101
+
102
+ subject.empty!('f.*')
103
+ end
104
+
105
+ context "when verbose is on" do
106
+ let(:outputter) { double("outputter") }
107
+
108
+ subject do
109
+ described_class.new(
110
+ http_client_factory: http_client_factory,
111
+ outputter: outputter,
112
+ verbose: true)
113
+ end
114
+
115
+ it "also outputs on STDOUT" do
116
+ http_client.stub(:delete)
117
+
118
+ outputter.should_receive(:puts).at_least(:once)
119
+ subject.empty!('f.*')
120
+ end
121
+ end
122
+ end
123
+
124
+ context "when given another host" do
125
+ let(:factory_for_remote_host) { double("http_client_factory") }
126
+
127
+ it "sends the other host's url to initialize the client" do
128
+ factory_for_remote_host.should_receive(:new).with("http://foobar.com")
129
+
130
+ described_class.new(host: "http://foobar.com", http_client_factory: factory_for_remote_host)
131
+ end
132
+ end
133
+
134
+ end
@@ -0,0 +1,11 @@
1
+ RSpec.configure do |config|
2
+ config.treat_symbols_as_metadata_keys_with_true_values = true
3
+ config.run_all_when_everything_filtered = true
4
+ config.filter_run :focus
5
+
6
+ # Run specs in random order to surface order dependencies. If you find an
7
+ # order dependency and want to debug it, you can fix the order by providing
8
+ # the seed, which is printed after each run.
9
+ # --seed 1234
10
+ config.order = 'random'
11
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: desi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -59,6 +59,54 @@ dependencies:
59
59
  - - ! '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: guard-rspec
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
62
110
  - !ruby/object:Gem::Dependency
63
111
  name: guard-yard
64
112
  requirement: !ruby/object:Gem::Requirement
@@ -119,6 +167,7 @@ extensions: []
119
167
  extra_rdoc_files: []
120
168
  files:
121
169
  - .gitignore
170
+ - .rspec
122
171
  - .yardopts
123
172
  - Gemfile
124
173
  - Guardfile
@@ -138,6 +187,8 @@ files:
138
187
  - lib/desi/runner.rb
139
188
  - lib/desi/upstream.rb
140
189
  - lib/desi/version.rb
190
+ - spec/desi/index_manager_spec.rb
191
+ - spec/spec_helper.rb
141
192
  - tasks/yard.rake
142
193
  homepage: https://github.com/AF83/desi/
143
194
  licenses: []
@@ -151,17 +202,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
151
202
  - - ! '>='
152
203
  - !ruby/object:Gem::Version
153
204
  version: '0'
205
+ segments:
206
+ - 0
207
+ hash: 1725098947325688636
154
208
  required_rubygems_version: !ruby/object:Gem::Requirement
155
209
  none: false
156
210
  requirements:
157
211
  - - ! '>='
158
212
  - !ruby/object:Gem::Version
159
213
  version: '0'
214
+ segments:
215
+ - 0
216
+ hash: 1725098947325688636
160
217
  requirements: []
161
218
  rubyforge_project:
162
219
  rubygems_version: 1.8.24
163
220
  signing_key:
164
221
  specification_version: 3
165
222
  summary: A developer tool to quickly set up an Elastic Search local install.
166
- test_files: []
223
+ test_files:
224
+ - spec/desi/index_manager_spec.rb
225
+ - spec/spec_helper.rb
167
226
  has_rdoc: