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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.agignore +1 -0
  3. data/README.md +24 -2
  4. data/Rakefile +1 -1
  5. data/bin/console +13 -0
  6. data/exe/solr-makr +9 -0
  7. data/lib/solr_makr.rb +76 -23
  8. data/lib/solr_makr/application.rb +24 -44
  9. data/lib/solr_makr/application_action.rb +182 -0
  10. data/lib/solr_makr/application_dispatch.rb +85 -0
  11. data/lib/solr_makr/collection.rb +17 -0
  12. data/lib/solr_makr/commands.rb +14 -0
  13. data/lib/solr_makr/commands/abstract_command.rb +60 -0
  14. data/lib/solr_makr/commands/buffer.rb +98 -0
  15. data/lib/solr_makr/commands/create_collection.rb +57 -0
  16. data/lib/solr_makr/commands/delete_collection.rb +13 -0
  17. data/lib/solr_makr/commands/execute.rb +67 -0
  18. data/lib/solr_makr/commands/fetch_collection_list.rb +17 -0
  19. data/lib/solr_makr/commands/push_config.rb +36 -0
  20. data/lib/solr_makr/commands/reload_collection.rb +13 -0
  21. data/lib/solr_makr/commands/set_up_local_configuration.rb +27 -0
  22. data/lib/solr_makr/commands/write_yaml.rb +28 -19
  23. data/lib/solr_makr/configsets.rb +15 -0
  24. data/lib/solr_makr/configsets/directory.rb +32 -0
  25. data/lib/solr_makr/configsets/get_nodes.rb +33 -0
  26. data/lib/solr_makr/configsets/install_default.rb +17 -0
  27. data/lib/solr_makr/configsets/lookup_dependent_collections.rb +20 -0
  28. data/lib/solr_makr/configsets/node.rb +56 -0
  29. data/lib/solr_makr/configsets/push_to_zookeeper.rb +19 -0
  30. data/lib/solr_makr/configsets/remote.rb +30 -0
  31. data/lib/solr_makr/configuration.rb +45 -0
  32. data/lib/solr_makr/errors/halt_execution.rb +4 -0
  33. data/lib/solr_makr/files/default-configset/README.md +1 -0
  34. data/lib/solr_makr/files/default-configset/conf/_rest_managed.json +1 -0
  35. data/lib/solr_makr/files/default-configset/conf/admin-extra.html +31 -0
  36. data/lib/solr_makr/files/default-configset/conf/currency.xml +67 -0
  37. data/lib/solr_makr/files/default-configset/conf/elevate.xml +1672 -0
  38. data/lib/solr_makr/files/default-configset/conf/lang/stopwords_en.txt +54 -0
  39. data/lib/solr_makr/files/default-configset/conf/mapping-ISOLatin1Accent.txt +2586 -0
  40. data/lib/solr_makr/files/default-configset/conf/protwords.txt +1613 -0
  41. data/lib/{files → solr_makr/files/default-configset/conf}/schema.xml +132 -40
  42. data/lib/solr_makr/files/default-configset/conf/scripts.conf +1623 -0
  43. data/lib/{files → solr_makr/files/default-configset/conf}/solrconfig.xml +294 -328
  44. data/lib/solr_makr/files/default-configset/conf/spellings.txt +1534 -0
  45. data/lib/solr_makr/files/default-configset/conf/synonyms.txt +1646 -0
  46. data/lib/solr_makr/local_configuration.rb +42 -0
  47. data/lib/solr_makr/local_configuration/cache.rb +21 -0
  48. data/lib/solr_makr/local_configuration/config_directory.rb +17 -0
  49. data/lib/solr_makr/local_configuration/directory.rb +17 -0
  50. data/lib/solr_makr/local_configuration/helper.rb +19 -0
  51. data/lib/solr_makr/local_configuration/save_settings.rb +9 -0
  52. data/lib/solr_makr/local_configuration/settings.rb +50 -0
  53. data/lib/solr_makr/meta/abstract_runner.rb +36 -0
  54. data/lib/solr_makr/meta/application_logger.rb +13 -0
  55. data/lib/solr_makr/meta/buffer_interaction.rb +41 -0
  56. data/lib/solr_makr/meta/disable_paging.rb +6 -0
  57. data/lib/solr_makr/meta/has_solr_attributes.rb +13 -0
  58. data/lib/solr_makr/meta/indifferent_options.rb +13 -0
  59. data/lib/solr_makr/meta/option_definition.rb +105 -0
  60. data/lib/solr_makr/meta/option_mapping.rb +38 -0
  61. data/lib/solr_makr/meta/pathlike.rb +9 -0
  62. data/lib/solr_makr/meta/set_global_options.rb +23 -0
  63. data/lib/solr_makr/meta/utility.rb +99 -0
  64. data/lib/solr_makr/meta/wraps_directory.rb +27 -0
  65. data/lib/solr_makr/meta/wraps_path.rb +18 -0
  66. data/lib/solr_makr/solr_api.rb +12 -0
  67. data/lib/solr_makr/solr_api/client.rb +32 -0
  68. data/lib/solr_makr/solr_api/client_macros.rb +61 -0
  69. data/lib/solr_makr/solr_api/cluster_response.rb +21 -0
  70. data/lib/solr_makr/solr_api/endpoint.rb +15 -0
  71. data/lib/solr_makr/solr_api/list_response.rb +19 -0
  72. data/lib/solr_makr/solr_api/request_params.rb +50 -0
  73. data/lib/solr_makr/solr_api/response.rb +69 -0
  74. data/lib/solr_makr/sunspot_configuration.rb +49 -0
  75. data/lib/solr_makr/version.rb +1 -1
  76. data/solr_makr.gemspec +17 -9
  77. metadata +171 -31
  78. data/bin/solr-makr +0 -7
  79. data/lib/solr_makr/commands/create_core.rb +0 -21
  80. data/lib/solr_makr/commands/destroy_core.rb +0 -17
  81. data/lib/solr_makr/commands/list_cores.rb +0 -17
  82. data/lib/solr_makr/commands/shared.rb +0 -84
  83. data/lib/solr_makr/core.rb +0 -94
  84. data/lib/solr_makr/core_status.rb +0 -56
  85. data/lib/solr_makr/solr_configuration.rb +0 -84
  86. data/lib/solr_makr/solr_request.rb +0 -23
@@ -0,0 +1,9 @@
1
+ module SolrMakr
2
+ class Pathlike < Virtus::Attribute
3
+ # @param [#to_s, Pathname]
4
+ # @return [Pathname]
5
+ def coerce(pathy)
6
+ return Pathname.new(pathy)
7
+ end
8
+ end
9
+ end
@@ -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,12 @@
1
+ module SolrMakr
2
+ module SolrAPI
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :Client
6
+ autoload :ClientMacros
7
+ autoload :RequestParams
8
+ autoload :Response
9
+ autoload :ClusterResponse
10
+ autoload :ListResponse
11
+ end
12
+ 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