solr_wrapper 0.0.7 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.hound.yml +2 -0
- data/.rspec +2 -0
- data/.rubocop.yml +16 -0
- data/.rubocop_todo.yml +0 -0
- data/.travis.yml +10 -5
- data/Gemfile +1 -1
- data/README.md +81 -6
- data/Rakefile +1 -2
- data/exe/solr_wrapper +125 -0
- data/lib/solr_wrapper/client.rb +36 -0
- data/lib/solr_wrapper/configuration.rb +163 -0
- data/lib/solr_wrapper/downloader.rb +25 -0
- data/lib/solr_wrapper/instance.rb +238 -175
- data/lib/solr_wrapper/md5.rb +43 -0
- data/lib/solr_wrapper/rake_task.rb +5 -0
- data/lib/solr_wrapper/settings.rb +148 -0
- data/lib/solr_wrapper/tasks/solr_wrapper.rake +45 -0
- data/lib/solr_wrapper/version.rb +2 -2
- data/lib/solr_wrapper.rb +32 -6
- data/solr_wrapper.gemspec +4 -1
- data/spec/fixtures/another_sample_config.yml +2 -0
- data/spec/fixtures/sample_config.yml +8 -0
- data/spec/lib/solr_wrapper/client_spec.rb +25 -0
- data/spec/lib/solr_wrapper/configuration_spec.rb +86 -0
- data/spec/lib/solr_wrapper/instance_spec.rb +154 -7
- data/spec/lib/solr_wrapper_spec.rb +18 -3
- data/spec/spec_helper.rb +5 -3
- metadata +54 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '092270d968ea024833bc6185caf854c05c8e623e'
|
|
4
|
+
data.tar.gz: 83d3dd71ca0de7c18ee9090a06ff051b174dbf4a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c4da5d83939b7d10b089d4453b79fb778aa499809cbd114d634fe8e7e790a21896c73320055fa43d3682559768fcb5729f2062bde7ab1ee9beeb92e967c1cf50
|
|
7
|
+
data.tar.gz: c7373e52dcd5520e541947655b1e95c6fcd53e9ccf7b356d7bf2efa37f60bb36555508451bc46546c92b3b1899859040453072802e54ba9fd59238fed106553d
|
data/.hound.yml
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.rubocop_todo.yml
ADDED
|
File without changes
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -11,18 +11,93 @@ end
|
|
|
11
11
|
Or with Solr and a solr collection:
|
|
12
12
|
|
|
13
13
|
```ruby
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
end
|
|
14
|
+
SolrWrapper.wrap do |solr|
|
|
15
|
+
solr.with_collection(dir: File.join(FIXTURES_DIR, "basic_configs")) do |collection_name|
|
|
17
16
|
end
|
|
17
|
+
end
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
## Basic Options
|
|
21
21
|
|
|
22
22
|
```ruby
|
|
23
|
-
SolrWrapper.wrap port: 8983,
|
|
23
|
+
SolrWrapper.wrap port: 8983,
|
|
24
|
+
verbose: true,
|
|
25
|
+
managed: true,
|
|
26
|
+
instance_dir: '/opt/solr'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Valid ruby and YAML options
|
|
30
|
+
|
|
31
|
+
|Option | |
|
|
32
|
+
|---------------|-----------------------------------------|
|
|
33
|
+
| instance_dir | Directory to store the solr index files |
|
|
34
|
+
| url | URL of the Zip file to download |
|
|
35
|
+
| version | Solr version to download and install |
|
|
36
|
+
| port | port to run Solr on |
|
|
37
|
+
| version_file | Local path to store the currently installed version |
|
|
38
|
+
| download_dir | Local path for storing the downloaded Solr zip file |
|
|
39
|
+
| solr_zip_path | Local path to the Solr zip file |
|
|
40
|
+
| md5sum | Path/URL to MD5 checksum |
|
|
41
|
+
| solr_xml | Path to Solr configuration |
|
|
42
|
+
| verbose | (Boolean) |
|
|
43
|
+
| managed | (Boolean) |
|
|
44
|
+
| ignore_md5sum | (Boolean) |
|
|
45
|
+
| solr_options | (Hash) |
|
|
46
|
+
| env | (Hash) |
|
|
47
|
+
| persist | (Boolean) Preserves the data in you collection between startups |
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
solr.with_collection(name: 'collection_name', dir: 'path_to_solr_configs')
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## From the command line
|
|
54
|
+
|
|
55
|
+
```console
|
|
56
|
+
$ solr_wrapper -p 8983
|
|
57
|
+
```
|
|
58
|
+
To see a list of valid options when using solr_wrapper to launch a Solr instance from the command line:
|
|
59
|
+
```
|
|
60
|
+
$ solr_wrapper -h
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Configuration file
|
|
64
|
+
SolrWrapper can read configuration options from a YAML configuration file.
|
|
65
|
+
By default, it looks for configuration files at `.solr_wrapper` and `~/.solr_wrapper`.
|
|
66
|
+
|
|
67
|
+
You can also specify a configuration file when launching from the command line as follows:
|
|
68
|
+
```
|
|
69
|
+
$ solr_wrapper -config <path_to_config_file>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Cleaning your repository from the command line
|
|
73
|
+
|
|
74
|
+
By defualt SorlWrapper will clean out your data when it shuts down.
|
|
75
|
+
If you utilize the preserve option your data will remain between runs.
|
|
76
|
+
|
|
77
|
+
To clean out data that is being preserved explicitly run:
|
|
78
|
+
```
|
|
79
|
+
$ solr_wrapper <configuration options> clean
|
|
80
|
+
```
|
|
81
|
+
***Note*** You must use the same configuration options on the clean command as you do on the run command to clean the correct instance.
|
|
82
|
+
|
|
83
|
+
## Rake tasks
|
|
84
|
+
|
|
85
|
+
SolrWrapper provides rake tasks for installing, starting and stopping solr. To include the tasks in your Rake environment, add this to your Rakefile
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
require 'solr_wrapper/rake_task'
|
|
24
89
|
```
|
|
25
90
|
|
|
91
|
+
You can configure the tasks by setting `SolrWrapper.default_instance_options`. For example:
|
|
92
|
+
|
|
26
93
|
```ruby
|
|
27
|
-
|
|
28
|
-
|
|
94
|
+
SolrWrapper.default_instance_options = {
|
|
95
|
+
verbose: true,
|
|
96
|
+
cloud: true,
|
|
97
|
+
port: '8888',
|
|
98
|
+
version: '5.3.1',
|
|
99
|
+
instance_dir: 'solr',
|
|
100
|
+
download_dir: 'tmp'
|
|
101
|
+
}
|
|
102
|
+
require 'solr_wrapper/rake_task'
|
|
103
|
+
```
|
data/Rakefile
CHANGED
data/exe/solr_wrapper
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'solr_wrapper'
|
|
4
|
+
require 'optparse'
|
|
5
|
+
|
|
6
|
+
options = {}
|
|
7
|
+
collection_options = {}
|
|
8
|
+
subtext = <<HELP
|
|
9
|
+
Commonly used command are:
|
|
10
|
+
clean : cleans all data from solr and configures a clean instance based on configuration options
|
|
11
|
+
dir : prints the solr instance dir
|
|
12
|
+
See 'solr_wrapper COMMAND --help' for more information on a specific command.
|
|
13
|
+
HELP
|
|
14
|
+
|
|
15
|
+
args = OptionParser.new do |opts|
|
|
16
|
+
opts.banner = "Usage: solr_wrapper [options] subcommand"
|
|
17
|
+
|
|
18
|
+
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
|
19
|
+
options[:verbose] = v
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
opts.on("--config FILE", "Load configuration from a file") do |v|
|
|
23
|
+
options[:config] = v
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
opts.on("--version VERSION", "Specify a Solr version to download (default: #{SolrWrapper.default_solr_version})") do |v|
|
|
27
|
+
options[:version] = v
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
opts.on("-pPORT", "--port PORT", "Specify the port Solr should run at (default: #{SolrWrapper.default_solr_port})") do |p|
|
|
31
|
+
if p == 'random'
|
|
32
|
+
options[:port] = nil
|
|
33
|
+
else
|
|
34
|
+
options[:port] = p
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
opts.on("-c", "--cloud", "Run solr in cloud mode") do |c|
|
|
39
|
+
options[:cloud] = c
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
opts.on("--solr_zip_path PATH", "Download/use solr at the given path") do |d|
|
|
43
|
+
options[:solr_zip_path] = d
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
opts.on("-iDIR", "--instance_directory DIR", "Install/use solr at the given directory") do |d|
|
|
47
|
+
options[:instance_dir] = d
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
opts.on("-lDIR", "--lib_directory DIR", "Grab extra libs from this directory") do |d|
|
|
51
|
+
options[:extra_lib_dir] = d
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
opts.on("-nNAME", "--collection_name NAME", "Create a default solr collection with the given name") do |c|
|
|
55
|
+
collection_options[:name] = c
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
opts.on("-dDIR", "--collection_config DIR", "Create a default solr collection with the files from the given directory") do |d|
|
|
59
|
+
collection_options[:dir] = d
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
opts.on("--[no-]persist", "Persist the solr connection data") do |d|
|
|
63
|
+
collection_options[:persist] = d
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
opts.on("--no-checksum", "Skip running checksum validation on the downloaded file") do |d|
|
|
67
|
+
options[:ignore_md5sum] = true
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
opts.separator ""
|
|
71
|
+
opts.separator subtext
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
subcommands = {
|
|
76
|
+
'clean' => OptionParser.new do |opts|
|
|
77
|
+
opts.banner = "Usage: clean"
|
|
78
|
+
end,
|
|
79
|
+
'dir' => OptionParser.new do |opts|
|
|
80
|
+
opts.banner = "Usage: dir"
|
|
81
|
+
end,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
begin
|
|
86
|
+
args.order!
|
|
87
|
+
command = ARGV.shift
|
|
88
|
+
if command
|
|
89
|
+
raise "Bad subcommand: #{command}" unless subcommands[command]
|
|
90
|
+
subcommands[command].order!
|
|
91
|
+
end
|
|
92
|
+
args.parse!
|
|
93
|
+
rescue => error
|
|
94
|
+
$stderr.puts "ERROR: #{error}\n"
|
|
95
|
+
$stderr.puts args.help
|
|
96
|
+
exit 1
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
instance = SolrWrapper.instance(options)
|
|
100
|
+
|
|
101
|
+
case command
|
|
102
|
+
when 'clean'
|
|
103
|
+
if instance.started?
|
|
104
|
+
$stderr.puts "Please stop solr before cleaning"
|
|
105
|
+
exit 1
|
|
106
|
+
end
|
|
107
|
+
$stderr.puts "cleaning #{instance.instance_dir}..."
|
|
108
|
+
instance.remove_instance_dir!
|
|
109
|
+
when 'dir'
|
|
110
|
+
puts instance.instance_dir
|
|
111
|
+
else
|
|
112
|
+
$stderr.print "Starting Solr #{instance.version} on port #{instance.port} ... "
|
|
113
|
+
instance.wrap do |conn|
|
|
114
|
+
conn.with_collection(collection_options) do
|
|
115
|
+
$stderr.puts "http://#{instance.host}:#{instance.port}/solr/"
|
|
116
|
+
begin
|
|
117
|
+
conn.wait
|
|
118
|
+
rescue Interrupt
|
|
119
|
+
Signal.trap("SIGTERM") {"IGNORE"}
|
|
120
|
+
Signal.trap("SIGINT") {"IGNORE"}
|
|
121
|
+
$stderr.puts "Solr is shutting down."
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module SolrWrapper
|
|
5
|
+
# Solr REST API client to get status information
|
|
6
|
+
class Client
|
|
7
|
+
attr_reader :url
|
|
8
|
+
|
|
9
|
+
def initialize(url)
|
|
10
|
+
@url = url
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Check if a core or collection exists
|
|
14
|
+
def exists?(core_or_collection_name)
|
|
15
|
+
collection?(core_or_collection_name) || core?(core_or_collection_name)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def collection?(name)
|
|
21
|
+
response = conn.get('admin/collections?action=LIST&wt=json')
|
|
22
|
+
data = JSON.parse(response.body)
|
|
23
|
+
return if data['error'] && data['error']['msg'] == 'Solr instance is not running in SolrCloud mode.'
|
|
24
|
+
data['collections'].include? name
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def core?(name)
|
|
28
|
+
response = conn.get('admin/cores?action=STATUS&wt=json&core=' + name)
|
|
29
|
+
!JSON.parse(response.body)['status'][name].empty?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def conn
|
|
33
|
+
@conn ||= Faraday.new(url: url)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
|
|
3
|
+
module SolrWrapper
|
|
4
|
+
class Configuration
|
|
5
|
+
attr_reader :options
|
|
6
|
+
|
|
7
|
+
def initialize(options = {})
|
|
8
|
+
@config = options[:config]
|
|
9
|
+
@verbose = options[:verbose]
|
|
10
|
+
|
|
11
|
+
@options = load_configs(Array(options[:config])).merge(options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def solr_xml
|
|
15
|
+
options[:solr_xml]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def extra_lib_dir
|
|
19
|
+
options[:extra_lib_dir]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def validate
|
|
23
|
+
options[:validate]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ignore_md5sum
|
|
27
|
+
options[:ignore_md5sum]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def md5sum
|
|
31
|
+
options[:md5sum]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def url
|
|
35
|
+
options[:url]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def port
|
|
39
|
+
# Check if the port option has been explicitly set to nil.
|
|
40
|
+
# this means to start solr wrapper on a random open port
|
|
41
|
+
return nil if options.key?(:port) && !options[:port]
|
|
42
|
+
options.fetch(:port) { SolrWrapper.default_instance_options[:port] }.to_s
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def zookeeper_host
|
|
46
|
+
options[:zookeeper_host]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def zookeeper_port
|
|
50
|
+
options[:zookeeper_port]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def solr_zip_path
|
|
54
|
+
options[:solr_zip_path]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def download_dir
|
|
58
|
+
options[:download_dir] || default_download_dir
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def default_download_dir
|
|
62
|
+
if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
|
|
63
|
+
File.join(Rails.root, 'tmp')
|
|
64
|
+
else
|
|
65
|
+
Dir.tmpdir
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def solr_options
|
|
70
|
+
options.fetch(:solr_options, {})
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def env
|
|
74
|
+
options.fetch(:env, {})
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def instance_dir
|
|
78
|
+
options[:instance_dir]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def version
|
|
82
|
+
@version ||= begin
|
|
83
|
+
config_version = options.fetch(:version, SolrWrapper.default_instance_options[:version])
|
|
84
|
+
if config_version == 'latest'
|
|
85
|
+
fetch_latest_version
|
|
86
|
+
else
|
|
87
|
+
config_version
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def mirror_url
|
|
93
|
+
"http://www.apache.org/dyn/closer.lua/lucene/solr/#{version}/solr-#{version}.zip?asjson=true"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def cloud
|
|
97
|
+
options[:cloud]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def verbose?
|
|
101
|
+
@verbose || (options && !!options.fetch(:verbose, false))
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def version_file
|
|
105
|
+
options[:version_file]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def collection_options
|
|
109
|
+
hash = options.fetch(:collection, {})
|
|
110
|
+
Configuration.slice(convert_keys(hash), :name, :dir, :persist)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def configsets
|
|
114
|
+
configsets = options[:configsets] || []
|
|
115
|
+
configsets.map { |x| convert_keys(x) }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def poll_interval
|
|
119
|
+
options.fetch(:poll_interval, 1)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
|
|
124
|
+
def self.slice(source, *keys)
|
|
125
|
+
keys.each_with_object({}) { |k, hash| hash[k] = source[k] if source.has_key?(k) }
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def load_configs(config_files)
|
|
129
|
+
config = {}
|
|
130
|
+
|
|
131
|
+
(default_configuration_paths + config_files.compact).each do |p|
|
|
132
|
+
path = File.expand_path(p)
|
|
133
|
+
next unless File.exist? path
|
|
134
|
+
config.merge!(read_config(path))
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
config
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def read_config(config_file)
|
|
141
|
+
$stdout.puts "Loading configuration from #{config_file}" if verbose?
|
|
142
|
+
config = YAML.load(ERB.new(IO.read(config_file)).result(binding))
|
|
143
|
+
unless config
|
|
144
|
+
$stderr.puts "Unable to parse config #{config_file}" if verbose?
|
|
145
|
+
return {}
|
|
146
|
+
end
|
|
147
|
+
convert_keys(config)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def convert_keys(hash)
|
|
151
|
+
hash.each_with_object({}) { |(k, v), h| h[k.to_sym] = v }
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def default_configuration_paths
|
|
155
|
+
['~/.solr_wrapper.yml', '~/.solr_wrapper', '.solr_wrapper.yml', '.solr_wrapper']
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def fetch_latest_version
|
|
159
|
+
response = Faraday.get('https://svn.apache.org/repos/asf/lucene/cms/trunk/content/latestversion.mdtext')
|
|
160
|
+
response.body.strip
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'ruby-progressbar'
|
|
2
|
+
|
|
3
|
+
module SolrWrapper
|
|
4
|
+
class Downloader
|
|
5
|
+
def self.fetch_with_progressbar(url, output)
|
|
6
|
+
pbar = SafeProgressBar.new(title: File.basename(url), total: nil, format: '%t: |%B| %p%% (%e )')
|
|
7
|
+
open(url, content_length_proc: ->(bytes) { pbar.total = bytes }, progress_proc: ->(bytes) { pbar.progress = bytes }) do |io|
|
|
8
|
+
IO.copy_stream(io, output)
|
|
9
|
+
end
|
|
10
|
+
rescue OpenURI::HTTPError => e
|
|
11
|
+
raise SolrWrapperError, "Unable to download solr from #{url}\n#{e.message}: #{e.io.read}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class SafeProgressBar < ProgressBar::Base
|
|
15
|
+
def progress=(new_progress)
|
|
16
|
+
self.total = new_progress if total <= new_progress
|
|
17
|
+
super
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def total=(new_total)
|
|
21
|
+
super if new_total && new_total > 0
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|