desi 0.0.2 → 0.1.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/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private --protected lib/**/*.rb - README.md LICENSE
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ guard 'yard' do
4
+ watch(%r{lib/.+\.rb})
5
+ end
data/README.md CHANGED
@@ -2,8 +2,56 @@
2
2
 
3
3
  Desi (Developper ElasticSearch Installer) is very simple tool to quickly set up
4
4
  an [Elastic Search](http://www.elasticsearch.org/) local install for
5
- development purposes. It will download and install ElasticSearch (the latest
6
- version by default) and let you start/stop/restart it.
5
+ development purposes.
6
+
7
+ It can:
8
+
9
+ * download and install ElasticSearch (the latest release by default)
10
+ * start/stop/restart it.
11
+ * do basic indices management (list, delete, empty a given set of indices)
12
+
13
+ It can be used both as a command-line tool and as a library.
14
+
15
+
16
+ ## Usage
17
+
18
+ $ desi list # List locally installed ElasticSearch releases
19
+ $ desi releases # List all upstream Elastic Search releases (latest 5 by default)
20
+ $ desi install [VERSION] # Install a specific version (latest by default)
21
+ $ desi start # Start a local 1-node cluster (noop if active)
22
+ $ desi restart # (Re)start cluster (even if active)
23
+ $ desi stop # Stop cluster
24
+ $ desi status [--host HOST] # Show running cluster info
25
+
26
+ $ desi indices "^foo" # List all indices whose name match /^foo/
27
+ $ desi indices "^foo" --delete # Delete all matching indices
28
+ $ desi indices "bar$" --empty # Remove all records from the matching
29
+ # indices
30
+
31
+ ## Examples
32
+
33
+ ### Currently installed releases
34
+
35
+ The current version is the one symlinked to `$HOME/elasticsearch/current`
36
+
37
+ * command-line
38
+
39
+ ```shell
40
+ $ desi list
41
+ Local ES installs (current one is tagged with '*'):
42
+ * elasticsearch-0.19.9 (/home/me/elasticsearch/elasticsearch-0.19.9)
43
+ - elasticsearch-0.19.8 (/home/me/elasticsearch/elasticsearch-0.19.8)
44
+ ```
45
+
46
+
47
+ * library
48
+
49
+ ```ruby
50
+ Desi::LocalInstall.new.releases.map(&:name) #=> ["elasticsearch-0.19.8", "elasticsearch-0.19.9"]
51
+ Desi::LocalInstall.new.releases.detect(&:current?).version #=> "0.19.9"
52
+ ```
53
+
54
+
7
55
 
8
56
  ## Installation
9
57
 
@@ -19,21 +67,10 @@ Or install it yourself as:
19
67
 
20
68
  $ gem install desi
21
69
 
22
- ## Usage
23
-
24
- $ desi list # List locally installed ElasticSearch versions
25
- $ desi releases # List all upstream Elastic Search releases (latest 5 by default)
26
- $ desi install [VERSION] # Install a specific version (latest by default)
27
- $ desi start # Start a local 1-node cluster (noop if active)
28
- $ desi restart # (Re)start cluster (even if active)
29
- $ desi stop # Stop cluster
30
- $ desi status # Show running cluster info
31
-
32
70
  ## TODO
33
71
 
34
72
  * add tests, dammit!
35
73
 
36
- * index management (list, create, delete ES indices)
37
74
  * `desi upgrade` (Upgrade to latest version and migrate data)
38
75
  * `desi switch VERSION` (Switch currently active ES version to VERSION)
39
76
  * plugin management ? (list, install, remove ES plugins)
data/Rakefile CHANGED
@@ -1,2 +1,4 @@
1
1
  #!/usr/bin/env rake
2
2
  require "bundler/gem_tasks"
3
+
4
+ FileList['tasks/**/*.rake'].each { |task| import task }
data/desi.gemspec CHANGED
@@ -13,6 +13,11 @@ an Elastic Search local install for development purposes.}
13
13
 
14
14
  gem.add_dependency "boson"
15
15
  gem.add_dependency "cocaine"
16
+ gem.add_dependency "addressable"
17
+
18
+ gem.add_development_dependency "guard-yard"
19
+ gem.add_development_dependency "redcarpet"
20
+ gem.add_development_dependency "rb-inotify"
16
21
 
17
22
  gem.files = `git ls-files`.split($\)
18
23
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
data/lib/desi.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  require "desi/version"
2
2
 
3
3
  module Desi
4
- autoload :Downloader, 'desi/downloader'
5
- autoload :HttpClient, 'desi/http_client'
6
- autoload :LocalInstall, 'desi/local_install'
7
- autoload :Upstream, 'desi/upstream'
8
- autoload :Installer, 'desi/installer'
9
- autoload :ProcessManager, 'desi/process_manager'
4
+ require 'desi/downloader'
5
+ require 'desi/http_client'
6
+ require 'desi/local_install'
7
+ require 'desi/upstream'
8
+ require 'desi/installer'
9
+ require 'desi/process_manager'
10
+ require 'desi/index_manager'
10
11
  end
11
12
 
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require "net/https"
4
- require "uri"
4
+ require "addressable/uri"
5
5
  require "json"
6
6
 
7
7
  module Desi
@@ -10,8 +10,8 @@ module Desi
10
10
 
11
11
  attr_reader :uri
12
12
 
13
- def initialize(uri)
14
- @uri = URI(uri)
13
+ def initialize(host_string)
14
+ @uri = to_uri(host_string)
15
15
 
16
16
  case @uri.scheme
17
17
  when 'https'
@@ -39,6 +39,31 @@ module Desi
39
39
  raise response.error!
40
40
  end
41
41
  end
42
+
43
+ def delete(uri)
44
+ response = @http.request(Net::HTTP::Delete.new(uri))
45
+
46
+ case response
47
+ when Net::HTTPSuccess
48
+ response
49
+ else
50
+ raise response.error!
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def to_uri(host_string)
57
+ scheme, host, port = ['http', '127.0.0.1', 9200]
58
+
59
+ %r{(?<scheme>(https?|))(?:\:\/\/|)(?<host>[^:]*?):?(?<port>\d*)/?$}.match(host_string) do |m|
60
+ scheme = m[:scheme] unless m[:scheme].empty?
61
+ host = m[:host] unless m[:host].empty?
62
+ port = m[:port] unless m[:port].empty?
63
+ end
64
+
65
+ Addressable::URI.new(scheme: scheme, host: host, port: port)
66
+ end
42
67
  end
43
68
 
44
69
  end
@@ -0,0 +1,114 @@
1
+ # encoding: utf-8
2
+
3
+ require "desi/http_client"
4
+
5
+ module Desi
6
+
7
+ # Performs some simple index-related operations on a local or distance
8
+ # Elastic Search cluster
9
+ class IndexManager
10
+
11
+ # Initializes a Desi::IndexManager instance
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
18
+ #
19
+ # @return [undefined]
20
+ #
21
+ # @api public
22
+ def initialize(opts = {})
23
+ @host = opts.fetch(:host, 'http://127.0.0.1:9200')
24
+ @verbose = opts[:verbose]
25
+ @client = Desi::HttpClient.new(@host)
26
+ end
27
+
28
+
29
+ # List index names for the specified cluster
30
+ #
31
+ # You can restrict the list using a regular expression pattern. (The default
32
+ # pattern being +/.*/+, all releases will be returned if you do not
33
+ # specify anything.)
34
+ #
35
+ # @param [#to_s] pattern Regexp pattern used to restrict the selection
36
+ # @return [Array<String>] List of index names of the ES cluster
37
+ #
38
+ # @note This method will also output its result on STDOUT if +@verbose+ is
39
+ # true
40
+ #
41
+ # @example List all indices whose name begins with "foo"
42
+ # Desi::IndexManager.new.list('^foo') #=> ["foo1", "foo2", "foo3"]
43
+ #
44
+ # @api public
45
+ def list(pattern = '.*')
46
+ pattern = Regexp.new(pattern || '.*')
47
+
48
+ puts "Indices from host #{@client.uri} matching the pattern #{pattern.inspect}\n\n" if @verbose
49
+
50
+ list = indices(pattern).sort
51
+ list.each {|i| puts i } if @verbose
52
+ list
53
+ end
54
+
55
+ # Delete all indices matching the specified pattern
56
+ #
57
+ # @param [#to_s] pattern Regexp pattern used to restrict the selection
58
+ # @return [undefined]
59
+ #
60
+ # @note No confirmation is needed, so beware!
61
+ #
62
+ # @note This method will also output its result on STDOUT if +@verbose+ is
63
+ # true
64
+ #
65
+ # @example Delete all indices whose name begins with "test"
66
+ # Desi::IndexManager.new.delete!('^test') #=> nil
67
+ #
68
+ # @api public
69
+ def delete!(pattern)
70
+ warn "You must provide a pattern" and exit if pattern.nil?
71
+
72
+ puts "The following indices from host #{@client.uri} are now deleted" if @verbose
73
+
74
+ indices(Regexp.new(pattern)).each do |index|
75
+ @client.delete(index)
76
+ puts " * #{index}" if @verbose
77
+ end
78
+ end
79
+
80
+ # Empty (remove all records) from indices matching the specified pattern
81
+ #
82
+ # @param [#to_s] pattern Regexp pattern used to restrict the selection
83
+ # @return [undefined]
84
+ #
85
+ # @note No confirmation is needed, so beware!
86
+ #
87
+ # @note This method will also output its result on STDOUT if +@verbose+ is
88
+ # true
89
+ #
90
+ # @example Empty all indices whose name begins with "log"
91
+ # Desi::IndexManager.new.empty!('^log') #=> nil
92
+ #
93
+ # @api public
94
+ def empty!(pattern)
95
+ warn "You must provide a pattern" and exit if pattern.nil?
96
+
97
+ puts "The following indices from host #{@client.uri} are now emptied" if @verbose
98
+
99
+ indices(Regexp.new(pattern)).each do |index|
100
+ @client.delete("#{index}/_query?q=*")
101
+ puts " * #{index}" if @verbose
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ def indices(pattern)
108
+ JSON.parse(@client.get('_status').body)["indices"].keys.select {|i|
109
+ i =~ pattern
110
+ }
111
+ end
112
+
113
+ end
114
+ end
@@ -1,9 +1,56 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require "pathname"
4
+
3
5
  module Desi
4
6
  class LocalInstall
5
7
  DEFAULT_DIR = '~/elasticsearch'
6
8
 
9
+ class Release
10
+ def self.all_in(workdir)
11
+ Dir[workdir.join('*')].
12
+ select {|subdir| File.directory?(subdir) && File.basename(subdir) =~ /^elasticsearch\-\d+\.\d+\.\d+/ }.
13
+ map {|dirname| new(dirname, workdir) }
14
+ end
15
+
16
+ def initialize(dirname, workdir)
17
+ @dirname = Pathname.new(dirname)
18
+ @workdir = workdir
19
+ end
20
+
21
+ def name
22
+ @name ||= File.basename(@dirname)
23
+ end
24
+
25
+ def current?
26
+ current_symlink? && current_symlink.realpath == @dirname
27
+ end
28
+
29
+ def version
30
+ @version ||= /^elasticsearch\-(?<version>.*)$/.match(name.to_s)[:version]
31
+ end
32
+
33
+ def to_s
34
+ current_mark = current? ? '*' : '-'
35
+
36
+ " #{current_mark} #{name} (#{@dirname})"
37
+ end
38
+
39
+ def <=>(other)
40
+ name <=> other.name
41
+ end
42
+
43
+ private
44
+
45
+ def current_symlink
46
+ @current_symlink ||= Pathname(@workdir).join('current')
47
+ end
48
+
49
+ def current_symlink?
50
+ current_symlink.exist?
51
+ end
52
+ end
53
+
7
54
  def initialize(workdir = nil)
8
55
  @workdir = Pathname(File.expand_path(workdir || DEFAULT_DIR))
9
56
  end
@@ -20,8 +67,8 @@ module Desi
20
67
  FileUtils.mkdir_p @workdir
21
68
  end
22
69
 
23
- def versions
24
- Dir[@workdir.join('*')].select {|subdir| File.directory?(subdir) && File.basename(subdir) =~ /^elasticsearch\-\d+\.\d+\.\d+/ }
70
+ def releases
71
+ Release.all_in(@workdir)
25
72
  end
26
73
 
27
74
  def to_path
@@ -3,14 +3,17 @@
3
3
  require "json"
4
4
  require "cocaine"
5
5
  require "ostruct"
6
+ require "desi/http_client"
7
+ require "desi/local_install"
6
8
 
7
9
  module Desi
8
10
  class ProcessManager
9
11
 
10
12
  def initialize(opts = {})
13
+ @host = opts.fetch(:host, 'http://127.0.0.1:9200')
11
14
  @verbose = opts[:verbose]
12
15
  @local_install = LocalInstall.new
13
- @client = Desi::HttpClient.new('http://localhost:9200/')
16
+ @client = Desi::HttpClient.new(@host)
14
17
  end
15
18
 
16
19
  def start
data/lib/desi/runner.rb CHANGED
@@ -13,9 +13,9 @@ module Desi
13
13
  desc "List locally installed Elastic Search releases"
14
14
  verbosity_option
15
15
  def list(options = {})
16
- puts "Local ES installs:" unless quiet?(options)
17
- Desi::LocalInstall.new.versions.each do |v|
18
- puts "* #{v}"
16
+ puts "Local ES installs (current one is tagged with '*'):" unless quiet?(options)
17
+ Desi::LocalInstall.new.releases.sort.reverse.each do |v|
18
+ puts v
19
19
  end
20
20
  end
21
21
 
@@ -31,7 +31,7 @@ module Desi
31
31
  releases
32
32
  else
33
33
  puts "Here are #{limit == 0 ? 'all the' : "the #{limit} latest"} releases"
34
- releases.each {|rel| puts " * #{rel.name} (#{rel.release_date})" }
34
+ releases.each {|rel| puts " - #{rel.name} (#{rel.release_date})" }
35
35
  end
36
36
  end
37
37
 
@@ -71,8 +71,26 @@ module Desi
71
71
 
72
72
  desc "Show current status"
73
73
  verbosity_option
74
+ option "--host", type: :string, desc: "Elastic Search cluster URL", default: '127.0.0.1:9200'
74
75
  def status(options = {})
75
- Desi::ProcessManager.new(verbose: !quiet?(options)).status
76
+ Desi::ProcessManager.new(verbose: !quiet?(options), host: options[:host]).status
77
+ end
78
+
79
+ desc "List indices"
80
+ verbosity_option
81
+ option "--host", type: :string, desc: "Elastic Search cluster URL", default: '127.0.0.1:9200'
82
+ option "--delete", type: :boolean, desc: "Delete the specified indices (You've been warned!)", default: false
83
+ option "--empty", type: :boolean, desc: "Delete all documents from the specified indices", default: false
84
+ def indices(pattern = nil, options = {})
85
+ index_manager = Desi::IndexManager.new(verbose: !quiet?(options), host: options[:host])
86
+
87
+ if options[:delete]
88
+ index_manager.delete!(pattern)
89
+ elsif options[:empty]
90
+ index_manager.empty!(pattern)
91
+ else
92
+ index_manager.list(pattern)
93
+ end
76
94
  end
77
95
 
78
96
  # desc "Upgrade to latest ElasticSearch version"
data/lib/desi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Desi
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
data/tasks/yard.rake ADDED
@@ -0,0 +1,9 @@
1
+ begin
2
+ require 'yard'
3
+
4
+ YARD::Rake::YardocTask.new
5
+ rescue LoadError
6
+ task :yard do
7
+ abort 'YARD is not available. In order to run yard, you must: gem install yard'
8
+ end
9
+ 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.0.2
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-17 00:00:00.000000000 Z
12
+ date: 2012-09-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: boson
@@ -43,6 +43,70 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: addressable
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: guard-yard
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: redcarpet
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: rb-inotify
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'
46
110
  description: ! 'Desi (Developper ElasticSearch Installer) is very simple tool to quickly
47
111
  set up
48
112
 
@@ -55,7 +119,9 @@ extensions: []
55
119
  extra_rdoc_files: []
56
120
  files:
57
121
  - .gitignore
122
+ - .yardopts
58
123
  - Gemfile
124
+ - Guardfile
59
125
  - LICENSE
60
126
  - README.md
61
127
  - Rakefile
@@ -65,12 +131,14 @@ files:
65
131
  - lib/desi.rb
66
132
  - lib/desi/downloader.rb
67
133
  - lib/desi/http_client.rb
134
+ - lib/desi/index_manager.rb
68
135
  - lib/desi/installer.rb
69
136
  - lib/desi/local_install.rb
70
137
  - lib/desi/process_manager.rb
71
138
  - lib/desi/runner.rb
72
139
  - lib/desi/upstream.rb
73
140
  - lib/desi/version.rb
141
+ - tasks/yard.rake
74
142
  homepage: https://github.com/AF83/desi/
75
143
  licenses: []
76
144
  post_install_message: