solr_makr 0.0.4 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.agignore +1 -0
- data/README.md +24 -2
- data/Rakefile +1 -1
- data/bin/console +13 -0
- data/exe/solr-makr +9 -0
- data/lib/solr_makr.rb +76 -23
- data/lib/solr_makr/application.rb +24 -44
- data/lib/solr_makr/application_action.rb +182 -0
- data/lib/solr_makr/application_dispatch.rb +85 -0
- data/lib/solr_makr/collection.rb +17 -0
- data/lib/solr_makr/commands.rb +14 -0
- data/lib/solr_makr/commands/abstract_command.rb +60 -0
- data/lib/solr_makr/commands/buffer.rb +98 -0
- data/lib/solr_makr/commands/create_collection.rb +57 -0
- data/lib/solr_makr/commands/delete_collection.rb +13 -0
- data/lib/solr_makr/commands/execute.rb +67 -0
- data/lib/solr_makr/commands/fetch_collection_list.rb +17 -0
- data/lib/solr_makr/commands/push_config.rb +36 -0
- data/lib/solr_makr/commands/reload_collection.rb +13 -0
- data/lib/solr_makr/commands/set_up_local_configuration.rb +27 -0
- data/lib/solr_makr/commands/write_yaml.rb +28 -19
- data/lib/solr_makr/configsets.rb +15 -0
- data/lib/solr_makr/configsets/directory.rb +32 -0
- data/lib/solr_makr/configsets/get_nodes.rb +33 -0
- data/lib/solr_makr/configsets/install_default.rb +17 -0
- data/lib/solr_makr/configsets/lookup_dependent_collections.rb +20 -0
- data/lib/solr_makr/configsets/node.rb +56 -0
- data/lib/solr_makr/configsets/push_to_zookeeper.rb +19 -0
- data/lib/solr_makr/configsets/remote.rb +30 -0
- data/lib/solr_makr/configuration.rb +45 -0
- data/lib/solr_makr/errors/halt_execution.rb +4 -0
- data/lib/solr_makr/files/default-configset/README.md +1 -0
- data/lib/solr_makr/files/default-configset/conf/_rest_managed.json +1 -0
- data/lib/solr_makr/files/default-configset/conf/admin-extra.html +31 -0
- data/lib/solr_makr/files/default-configset/conf/currency.xml +67 -0
- data/lib/solr_makr/files/default-configset/conf/elevate.xml +1672 -0
- data/lib/solr_makr/files/default-configset/conf/lang/stopwords_en.txt +54 -0
- data/lib/solr_makr/files/default-configset/conf/mapping-ISOLatin1Accent.txt +2586 -0
- data/lib/solr_makr/files/default-configset/conf/protwords.txt +1613 -0
- data/lib/{files → solr_makr/files/default-configset/conf}/schema.xml +132 -40
- data/lib/solr_makr/files/default-configset/conf/scripts.conf +1623 -0
- data/lib/{files → solr_makr/files/default-configset/conf}/solrconfig.xml +294 -328
- data/lib/solr_makr/files/default-configset/conf/spellings.txt +1534 -0
- data/lib/solr_makr/files/default-configset/conf/synonyms.txt +1646 -0
- data/lib/solr_makr/local_configuration.rb +42 -0
- data/lib/solr_makr/local_configuration/cache.rb +21 -0
- data/lib/solr_makr/local_configuration/config_directory.rb +17 -0
- data/lib/solr_makr/local_configuration/directory.rb +17 -0
- data/lib/solr_makr/local_configuration/helper.rb +19 -0
- data/lib/solr_makr/local_configuration/save_settings.rb +9 -0
- data/lib/solr_makr/local_configuration/settings.rb +50 -0
- data/lib/solr_makr/meta/abstract_runner.rb +36 -0
- data/lib/solr_makr/meta/application_logger.rb +13 -0
- data/lib/solr_makr/meta/buffer_interaction.rb +41 -0
- data/lib/solr_makr/meta/disable_paging.rb +6 -0
- data/lib/solr_makr/meta/has_solr_attributes.rb +13 -0
- data/lib/solr_makr/meta/indifferent_options.rb +13 -0
- data/lib/solr_makr/meta/option_definition.rb +105 -0
- data/lib/solr_makr/meta/option_mapping.rb +38 -0
- data/lib/solr_makr/meta/pathlike.rb +9 -0
- data/lib/solr_makr/meta/set_global_options.rb +23 -0
- data/lib/solr_makr/meta/utility.rb +99 -0
- data/lib/solr_makr/meta/wraps_directory.rb +27 -0
- data/lib/solr_makr/meta/wraps_path.rb +18 -0
- data/lib/solr_makr/solr_api.rb +12 -0
- data/lib/solr_makr/solr_api/client.rb +32 -0
- data/lib/solr_makr/solr_api/client_macros.rb +61 -0
- data/lib/solr_makr/solr_api/cluster_response.rb +21 -0
- data/lib/solr_makr/solr_api/endpoint.rb +15 -0
- data/lib/solr_makr/solr_api/list_response.rb +19 -0
- data/lib/solr_makr/solr_api/request_params.rb +50 -0
- data/lib/solr_makr/solr_api/response.rb +69 -0
- data/lib/solr_makr/sunspot_configuration.rb +49 -0
- data/lib/solr_makr/version.rb +1 -1
- data/solr_makr.gemspec +17 -9
- metadata +171 -31
- data/bin/solr-makr +0 -7
- data/lib/solr_makr/commands/create_core.rb +0 -21
- data/lib/solr_makr/commands/destroy_core.rb +0 -17
- data/lib/solr_makr/commands/list_cores.rb +0 -17
- data/lib/solr_makr/commands/shared.rb +0 -84
- data/lib/solr_makr/core.rb +0 -94
- data/lib/solr_makr/core_status.rb +0 -56
- data/lib/solr_makr/solr_configuration.rb +0 -84
- data/lib/solr_makr/solr_request.rb +0 -23
@@ -0,0 +1,23 @@
|
|
1
|
+
module SolrMakr
|
2
|
+
class SetGlobalOptions < ActiveInteraction::Base
|
3
|
+
with_options default: nil do
|
4
|
+
string :solr_host, strip: true
|
5
|
+
string :solr_path, strip: true
|
6
|
+
integer :solr_port
|
7
|
+
|
8
|
+
string :zookeeper, strip: true
|
9
|
+
end
|
10
|
+
|
11
|
+
validates_numericality_of :solr_port, integer_only: true,
|
12
|
+
greater_than_or_equal_to: 1,
|
13
|
+
less_than_or_equal_to: 65535,
|
14
|
+
message: 'must be a valid port',
|
15
|
+
allow_nil: true
|
16
|
+
|
17
|
+
def execute
|
18
|
+
inputs.each do |(setting, value)|
|
19
|
+
SolrMakr.configuration[setting] = value if given?(setting)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module SolrMakr
|
2
|
+
module Utility
|
3
|
+
module_function
|
4
|
+
|
5
|
+
# These are the minimum files required to configure a collection.
|
6
|
+
REQUIRED_SOLR_NODES = %w[schema.xml solrconfig.xml]
|
7
|
+
|
8
|
+
def default_table_options!(**table_options)
|
9
|
+
table_options[:style] ||= {}
|
10
|
+
|
11
|
+
width = table_options.delete(:width)
|
12
|
+
|
13
|
+
unless width == false
|
14
|
+
table_options[:style].reverse_merge! width: width || 80
|
15
|
+
end
|
16
|
+
|
17
|
+
return table_options
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param [#each] collection
|
21
|
+
# @param [String] if_blank
|
22
|
+
# @param [Hash] table_options option that get passed to the `Terminal::Table` constructor
|
23
|
+
# @yieldparam [Terminal::Table] t
|
24
|
+
# @yieldparam [Array, #to_a, Object] item
|
25
|
+
# @return [Terminal::Table]
|
26
|
+
def default_table(collection:, if_blank: 'n/a', **table_options, &formatter)
|
27
|
+
table_options = default_table_options!(table_options)
|
28
|
+
|
29
|
+
return if_blank if collection.blank?
|
30
|
+
|
31
|
+
Terminal::Table.new table_options do |t|
|
32
|
+
collection.each do |item|
|
33
|
+
if block_given?
|
34
|
+
if formatter.arity == 2
|
35
|
+
formatter.call(t, item)
|
36
|
+
else
|
37
|
+
t << yield(item)
|
38
|
+
end
|
39
|
+
elsif item.respond_to? :to_table_row
|
40
|
+
t << item.to_table_row
|
41
|
+
else
|
42
|
+
t << Array(item)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def hash_to_table(hsh, if_blank: 'n/a', **table_options)
|
49
|
+
hsh = hsh.to_h
|
50
|
+
|
51
|
+
table_options = default_table_options!(table_options)
|
52
|
+
|
53
|
+
if hsh.present?
|
54
|
+
Terminal::Table.new table_options do |t|
|
55
|
+
hsh.each do |key, value|
|
56
|
+
t << [key.inspect, value.inspect]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
else
|
60
|
+
if_blank
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# It's possible the root directory is not what actually contains the nodes
|
65
|
+
# for configuring solr (e.g. files are in a `conf` directory). For now let's
|
66
|
+
# use `Pathname#find` to figure it out.
|
67
|
+
#
|
68
|
+
# @param [Pathname] root
|
69
|
+
# @return [Pathname]
|
70
|
+
# @return [nil]
|
71
|
+
def path_to_configset(root)
|
72
|
+
root.find do |path|
|
73
|
+
return path.dirname if path.basename.to_s.in?(REQUIRED_SOLR_NODES)
|
74
|
+
end
|
75
|
+
|
76
|
+
return nil
|
77
|
+
end
|
78
|
+
|
79
|
+
# @param [Pathname] conf_path
|
80
|
+
# @yield called once for each missing node
|
81
|
+
# @yieldparam [String] name
|
82
|
+
# @yieldreturn [void]
|
83
|
+
def looks_like_a_valid_configset?(conf_path)
|
84
|
+
if conf_path.present? && conf_path.try(:exist?)
|
85
|
+
missing = REQUIRED_SOLR_NODES.reject do |file|
|
86
|
+
conf_path.join(file).exist?
|
87
|
+
end
|
88
|
+
|
89
|
+
missing.each do |name|
|
90
|
+
yield name if block_given?
|
91
|
+
end
|
92
|
+
|
93
|
+
return missing.none?
|
94
|
+
else
|
95
|
+
false
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SolrMakr
|
2
|
+
module WrapsDirectory
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
include SolrMakr::WrapsPath
|
6
|
+
|
7
|
+
included do
|
8
|
+
delegate :join, to: :path
|
9
|
+
end
|
10
|
+
|
11
|
+
# @return [Boolean] if created
|
12
|
+
def create_if_missing!
|
13
|
+
unless exists?
|
14
|
+
path.mkpath
|
15
|
+
|
16
|
+
true
|
17
|
+
else
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [<Pathname>]
|
23
|
+
def subdirectories
|
24
|
+
path.children.select(&:directory?)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SolrMakr
|
2
|
+
module WrapsPath
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include ActiveSupport::Configurable
|
5
|
+
|
6
|
+
included do
|
7
|
+
delegate :exist?, to: :path
|
8
|
+
alias_method :exists?, :exist?
|
9
|
+
end
|
10
|
+
|
11
|
+
# @!attribute [r] path
|
12
|
+
# @return [Pathname]
|
13
|
+
|
14
|
+
def inspect
|
15
|
+
"#<#{self.class.name} :path => '#{path.to_s}'>"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module SolrMakr
|
2
|
+
module SolrAPI
|
3
|
+
class Client
|
4
|
+
include HTTParty
|
5
|
+
include SolrMakr::SolrAPI::ClientMacros
|
6
|
+
|
7
|
+
#logger ::Logger.new(STDOUT)
|
8
|
+
|
9
|
+
# Specify the return type should be JSON, not XML.
|
10
|
+
default_params wt: 'json'
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
self.class.base_uri SolrMakr.configuration.solr_uri
|
14
|
+
end
|
15
|
+
|
16
|
+
define_collection_action! :cluster_status, action: 'CLUSTERSTATUS'
|
17
|
+
|
18
|
+
define_collection_action! :create, requires_name: true do |params, options|
|
19
|
+
params[:numShards] = options.fetch(:number_of_shards, 1)
|
20
|
+
params[:replicationFactor] = options.fetch(:replication_factor, 1)
|
21
|
+
params[:maxShardsPerNode] = options.fetch(:max_shards_per_node, 1)
|
22
|
+
params['collection.configName'] = options.fetch(:config_name, options.fetch(:name))
|
23
|
+
end
|
24
|
+
|
25
|
+
define_collection_action! :delete, requires_name: true
|
26
|
+
|
27
|
+
define_collection_action! :list
|
28
|
+
|
29
|
+
define_collection_action! :reload, requires_name: true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module SolrMakr
|
2
|
+
module SolrAPI
|
3
|
+
# @api private
|
4
|
+
module ClientMacros
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
class_methods do
|
8
|
+
# Generate a method to connect with the solr collections API.
|
9
|
+
#
|
10
|
+
# @param [String] name a ruby-safe name for the generated method
|
11
|
+
# @param [String] action the name of the action on in the solr API, all upper-case
|
12
|
+
# @param [:get, :post, :put, :delete] method the HTTP verb
|
13
|
+
# @param [Boolean] requires_name whether the `action` requires a collection name to be passed.
|
14
|
+
# Cluster-level actions, like `list` and `cluster_status`, do not.
|
15
|
+
# @param [Class, String, Symbol] response_klass
|
16
|
+
# @yield Allows the method to be further customized by formatting params passed to the
|
17
|
+
# API based on options provided to the generated method.
|
18
|
+
# @yieldparam [SolrMakr::SolrRequestParams] params
|
19
|
+
# @yieldparam [Hash] options
|
20
|
+
# @yieldreturn [void]
|
21
|
+
# @return [void]
|
22
|
+
# @!macro [attach] define_collection_action!
|
23
|
+
# @!method $1(options = {})
|
24
|
+
# @param [Hash] options
|
25
|
+
# @option options [String] :name the name of the collection
|
26
|
+
# @return [SolrMakr::SolrAPI::Response]
|
27
|
+
def define_collection_action!(name, action: name.to_s.upcase, method: :get, requires_name: false, response_klass: SolrMakr::SolrAPI::Response, &option_parser)
|
28
|
+
response_klass = parse_response_klass(response_klass)
|
29
|
+
|
30
|
+
define_method(name) do |**options|
|
31
|
+
params = SolrMakr::SolrAPI::RequestParams.new action: action
|
32
|
+
|
33
|
+
if requires_name
|
34
|
+
unless options.key?(:name) && options[:name].present?
|
35
|
+
raise ArgumentError, "missing required option: #{name}"
|
36
|
+
else
|
37
|
+
params[:name] = options[:name]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
if option_parser.respond_to?(:call)
|
42
|
+
option_parser.call(params, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
response = self.class.__send__(method, '/admin/collections', params)
|
46
|
+
|
47
|
+
response_klass.new(response)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @param [Class, String, Symbol] klass
|
52
|
+
# @return [Class]
|
53
|
+
def parse_response_klass(klass)
|
54
|
+
return klass if klass.kind_of?(Class)
|
55
|
+
|
56
|
+
"SolrMakr::SolrAPI::#{klass}".constantize
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SolrMakr
|
2
|
+
module SolrAPI
|
3
|
+
class ClusterResponse < Response
|
4
|
+
# @!attribute [r] collections
|
5
|
+
# @return [ActiveSupport::HashWithIndifferentAccess]
|
6
|
+
attr_lazy_reader :collections do
|
7
|
+
dig(:cluster, :collections) || {}.with_indifferent_access
|
8
|
+
end
|
9
|
+
|
10
|
+
def each_collection
|
11
|
+
return enum_for(__method__) unless block_given?
|
12
|
+
|
13
|
+
collections = dig(:cluster, :collections)
|
14
|
+
|
15
|
+
collections.each do |(key, info)|
|
16
|
+
yield key, info
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SolrMakr
|
2
|
+
module SolrAPI
|
3
|
+
# @abstract
|
4
|
+
class Endpoint
|
5
|
+
include Virtus.model strict: true
|
6
|
+
|
7
|
+
attribute :name, String
|
8
|
+
attribute :path, String
|
9
|
+
|
10
|
+
# @return [SolrMakr::SolrAPI::Response]
|
11
|
+
def request(client:, method:, response_klass:, params:)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SolrMakr
|
2
|
+
module SolrAPI
|
3
|
+
class ListResponse < Response
|
4
|
+
# @return [<String>]
|
5
|
+
attr_lazy_reader :collections do
|
6
|
+
array(:collections)
|
7
|
+
end
|
8
|
+
|
9
|
+
# @yieldparam [String]
|
10
|
+
def each_collection
|
11
|
+
return enum_for(__method__) unless block_given?
|
12
|
+
|
13
|
+
collections.each do |collection|
|
14
|
+
yield collection
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module SolrMakr
|
2
|
+
module SolrAPI
|
3
|
+
# Wrapper around parameters passed to solr api requests.
|
4
|
+
#
|
5
|
+
# Solr requests are not really RESTful, and instead take the action
|
6
|
+
# name in a parameter on the query string.
|
7
|
+
class RequestParams
|
8
|
+
# @param [String] action (see #action)
|
9
|
+
def initialize(action:)
|
10
|
+
@action = action
|
11
|
+
@query = {}.with_indifferent_access
|
12
|
+
@params = {}.with_indifferent_access
|
13
|
+
end
|
14
|
+
|
15
|
+
# @!attribute [r] action
|
16
|
+
# The name of the solr action, which is automatically applied to the
|
17
|
+
# {#query query string parameters} when the request is made.
|
18
|
+
# @return [String]
|
19
|
+
attr_reader :action
|
20
|
+
|
21
|
+
# @!attribute [r] params
|
22
|
+
# @api private
|
23
|
+
# @return [ActiveSupport::HashWithIndifferentAccess]
|
24
|
+
attr_reader :params
|
25
|
+
|
26
|
+
# @!attribute [r] query
|
27
|
+
# @return [ActiveSupport::HashWithIndifferentAccess]
|
28
|
+
attr_reader :query
|
29
|
+
|
30
|
+
delegate :[], :[]=, to: :query
|
31
|
+
|
32
|
+
# Set the body for the request.
|
33
|
+
#
|
34
|
+
# @param [String, #to_s]
|
35
|
+
# @return [void]
|
36
|
+
def body(request_body)
|
37
|
+
@params[:body] = request_body
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_h(options = nil)
|
41
|
+
query[:action] = @action
|
42
|
+
|
43
|
+
@params.to_h.merge(query: query)
|
44
|
+
end
|
45
|
+
|
46
|
+
alias_method :to_hash, :to_h
|
47
|
+
alias_method :as_json, :to_h
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module SolrMakr
|
2
|
+
module SolrAPI
|
3
|
+
class Response
|
4
|
+
# @param [Hash] raw_response
|
5
|
+
def initialize(raw_response = {})
|
6
|
+
@raw_response = raw_response.with_indifferent_access
|
7
|
+
end
|
8
|
+
|
9
|
+
# @!attribute [r] raw_response
|
10
|
+
# @return [ActiveSupport::HashWithIndifferentAccess]
|
11
|
+
attr_reader :raw_response
|
12
|
+
|
13
|
+
delegate :fetch, to: :raw_response
|
14
|
+
|
15
|
+
# @param [<String, Symbol>] keys path to the desired array
|
16
|
+
# @return [Array]
|
17
|
+
def array(*keys)
|
18
|
+
Array(dig(*keys))
|
19
|
+
end
|
20
|
+
|
21
|
+
# Dig into the response data by a given path.
|
22
|
+
#
|
23
|
+
# @param [<String, Symbol>] keys path to the desired value
|
24
|
+
# @return [Object] if non-hashlike
|
25
|
+
# @return [ActiveSupport::HashWithIndifferentAccess] if hash-like
|
26
|
+
def dig(*keys)
|
27
|
+
keys.reduce raw_response do |hsh, key|
|
28
|
+
hsh[key] if hsh.respond_to?(:[])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
alias_method :[], :dig
|
33
|
+
|
34
|
+
# @!attribute [r] response_header
|
35
|
+
# @return [ActiveSupport::HashWithIndifferentAccess]
|
36
|
+
attr_lazy_reader :response_header do
|
37
|
+
dig :responseHeader
|
38
|
+
end
|
39
|
+
|
40
|
+
# @!attribute [r] failure
|
41
|
+
# @return [String]
|
42
|
+
attr_lazy_reader :failure do
|
43
|
+
unless success?
|
44
|
+
exception.fetch(:msg) or error.fetch(:msg) or 'unknown failure'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_lazy_reader :error do
|
49
|
+
fetch(:error, {})
|
50
|
+
end
|
51
|
+
|
52
|
+
attr_lazy_reader :exception do
|
53
|
+
fetch(:exception, {})
|
54
|
+
end
|
55
|
+
|
56
|
+
def success?
|
57
|
+
status == 0
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_lazy_reader :status do
|
61
|
+
response_header.fetch :status, 500
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_s
|
65
|
+
"#<#{self.class.name} #{JSON.pretty_generate(raw_response)}>"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|