solr_cloud-connection 0.1.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1989962c4834b362be714c08199791950034638d4e2ea26bfa1368e377390f3b
4
- data.tar.gz: ed3621358d19671db37394b04b0df83e700b2dbd7b45dc7cd3e545c782ed64c6
3
+ metadata.gz: e273d22bc3c74c27f96e2e4441695c47c8561634d339b8dabdc0d9c0075922e6
4
+ data.tar.gz: e208564f23b12ad6554a075caf48f65d57e7dfbe15b800e85eb639f4d2dc6791
5
5
  SHA512:
6
- metadata.gz: 6161fb600d516c459a843f9f8054cf2b3db2cb0eadf04678af037b7bc55e86b828b08e167f01391dbb9b7b2d4c5a5759851fc322a71a8d545651734e44df978c
7
- data.tar.gz: 7082a625e5ffa7f04e17638db3782b0ac3715a3955413539543e39297cb589825cde87abd06dc2aff1cde7c59581da25a4d6fb372c7f3b177d780e035a5d1bdd
6
+ metadata.gz: 7a1ba3738d5908c753c49b6f813b14465ddb4213d925aa7c075d6665c01229d0aecd59b8479bf5ae54f1d94511579876e7d3c392847f1c0845eb130a0f9c0897
7
+ data.tar.gz: 14f6c01885f6d97b477311099e4399b9e74c400fce40c42cdccb3e56a798df3f0ce8b0475aa57299ad3054681c4de059bf80908102a9b98b3b67cd14ecbfb50b
@@ -1,3 +1,3 @@
1
- SOLR_URL=http://localhost:8983
2
- SOLR_USER=solr
1
+ SOLR_URL="http://localhost:8983"
3
2
  SOLR_PASSWORD=SolrRocks
3
+ SOLR_USER=solr
data/CHANGELOG.md CHANGED
@@ -1,4 +1,19 @@
1
- ## [Unreleased]
1
+ # Changelog
2
+
3
+ ## [0.3.0] - 2023-12-06
4
+
5
+ - Major overhaul of the interface to use more-explicit and less-confusing method names
6
+ - Remove code that tried to "version" collections and configsets, since it was dumb
7
+ - Get github actions working to run tests
8
+ - Make aliases even more of a paper-thin wrapper around collections, such that, e.g.
9
+ `coll = get_collection(alias_name)` will return the appropriate alias. Use
10
+ `coll.alias?` to determine if it's an alias or collection if that becomes important.
11
+
12
+ ## [0.2.0] - 2023-12-01
13
+
14
+ - Added options `:date` and `:datetime` to the `version:` argument to `create_collection`
15
+ to automatically generate, e.g., "2023-12-01" or "2023-12-01-09-50-56"
16
+ - Added utility method `legal_solr_name?` to check for validity for collection names
2
17
 
3
18
  ## [0.1.0] - 2023-11-29
4
19
 
data/README.md CHANGED
@@ -2,150 +2,108 @@
2
2
 
3
3
  Do basic administrative tasks on a running Solr cloud instance, including:
4
4
 
5
+ * create (i.e., upload) a configSet when given a `conf` directory
5
6
  * list, create, and delete configsets, collections, and aliases
6
7
  * get basic version information for the running solr
7
8
  * check on the health of individual collections
8
- * treat an alias (mostly) as a collection, just as you'd expect
9
+ * treat an alias (mostly) as a collection
9
10
  * TODO automatically generate methods to talk to defined requestHandlers
10
- * TODO collect and deal with search results in a sane way
11
+ * TODO Add something useful for configsets to do
12
+
13
+ In almost all cases, you can treat an alias to a collection like the underlying collection.
14
+
15
+ ## A note about deleting things
16
+
17
+ Collections, aliases, and configsets all have a `#delete!` method. Keep in mind that solr
18
+ enforces a rule that nothing in-use can be deleted. This gem will throw appropriate errors
19
+ if you try to delete a configset that's being used by a collection, or try to delete
20
+ a collections that's pointed to by an alias.
11
21
 
12
22
  ## Caveats
13
23
 
14
- * At this point the API is unstable, and it doesn't do any actual, you know, searching.
15
- * Due to there not being any sense of an atomic action when administering solr, this gem does
16
- _no caching_. This means the individual actions can involve several round-trips to solr. On the flip
17
- side, if you're doing so much admin that it's a bottleneck, you're well outside this gem's target case.
24
+ * At this point the API is unstable
25
+ * Performance is desperately, hilariously terrible. Solr has no sense of an atomic action and plenty of other ways
26
+ (e.g, the admin interface) to mess with things, so nothing is cached.
27
+ This means that individual actions can involve several round-trips to solr. If you're doing so much admin
28
+ that this becomes a bottleneck, you're well outside this gem's target case.
18
29
  * While solr aliases can point to more than one collection at a time, this gem enforces one collection
19
30
  per alias (although many aliases can point to the same collection)
20
31
 
21
32
  ## Usage
22
33
 
23
- ### Create a connection to a running solr
24
-
25
- The connection object is the basis of all the other stuff. Everything will be created, directly
26
- or indirectly, through the connection. While using the collection/alias/configset objects
27
- is preferred, the connection on its own can do most anything. See SolrCloud::Connection for
28
- the docs.
29
-
30
- A simple connection is made if you pass in basic info, or you can create a faraday connection
31
- and pass it in yourself.
34
+ The code below covers all the basics. See the docs for full sets of parameters, which errors are
35
+ thrown, etc.
32
36
 
33
37
  ```ruby
34
38
 
35
39
  require "solr_cloud/connection"
36
40
 
37
- solr = SolrCloud::connect.new(url: "http://localhost:9999", username: "user", password: "password")
38
- # #=> <SolrCloud::Connection http://localhost:9999/>
41
+ server = SolrCloud::connect.new(url: "http://localhost:8023", username: "user", password: "password")
42
+ # #=> <SolrCloud::Connection http://localhost:8023/>
39
43
 
40
44
  # or bring your own Faraday object
41
- solr = SolrCloud::connect.new_with_faraday(faraday_connection)
42
-
43
- ```
44
-
45
- ### Configsets
46
-
47
- Configuration sets can be created by giving a path to the `conf` directory (with
48
- `solrconfig.xml` and the schema and such) and a name.
49
-
50
- ```ruby
51
- connect.configset_names #=> []
52
- cset = connect.create_configset(name: "myconfig", confdir: "/path/to/yourconfig/conf")
53
-
54
- # Get a list of existing configsets
55
- arr_of_configsets_objects = @connect.configsets
56
- arr_of_names_as_strings = @connect.configset_names
57
-
58
- # Test and see if it exists by name
59
- connect.configset?("myconfig") #=> true
60
-
61
- # If it already exists, you can just grab it by name
62
-
63
- def_config = connect.configset("_default")
45
+ # server = SolrCloud::connect.new_with_faraday(faraday_connection)
64
46
 
65
- # It makes sure you don't overwrite when creating a new set
66
- connect.create_configset(name: "myconfig", confdir: "/path/to/yourconfig/conf")
67
- #=> WontOverwriteError
47
+ server.configset_names #=> ["_default"]
48
+ default = server.get_configset("_default") #=> <SolrCloud::Configset '_default' at http://localhost:8983>
68
49
 
69
- # ...but you can force it
70
- connect.create_configset(name: "myconfig", confdir: "/path/to/yourconfig/conf", force: true)
50
+ # Create a new one by taking a directory, zipping it up, and sending it to solr
51
+ cset = server.create_configset(name: "my_awesome_configset_for_cars", confdir: "/path/to/mycore/conf")
52
+ server.configset_names #=> ["_default", "my_awesome_configset_for_cars"]
71
53
 
72
- # And get rid of it
73
- myconfig.delete!
74
- connect.configset?("myconfig") #=> false
54
+ # That's a dumb name. We'll try again.
55
+ cset.delete!
56
+ cset = server.create_configset(name: "cars_config", confdir: "/path/to/mycore/conf")
75
57
 
76
- ```
77
-
78
- ### Collections
79
-
80
- Collections can be listed, tested for health and aliases, used to create an alias, and deleted.
81
-
82
- ```ruby
83
-
84
- connect.collection_names #=> []
85
- connect.create_collection(name: "mycoll", configset: "does_not_exist") #=> SolrCloud::NoSuchConfigSetError: Configset does_not_exist doesn't exist
86
- mycoll = connect.create_collection(name: "mycoll", configset: "_default")
87
- mycoll.name #=> "mycoll"
58
+ # Collections and aliases are mostly treated the same
59
+ server.collection_names #=> ["cars_v1", "cars_v2", "cars"] -- collections AND aliases
60
+ server.only_collection_names #=> ["cars_v1", "cars_v2"]
61
+ server.alias_names #=> ["cars"]
88
62
 
89
- # Test and see if it exists
90
- connect.collection?("mycoll") #=> true
63
+ typo = server.get_collection("cars__V2") #=> nil, doesn't exist
64
+ cars_v2 = server.get_collection("cars_v2")
91
65
 
92
- # Get all of them
66
+ cars_v2.alive? #=> true
67
+ cars_v2.count #=> 133 -- we're assuming there's stuff in it.
93
68
 
94
- arr_of_collection_objects = connect.collections
95
- arr_of_names_as_strings = connect.collection_names
96
69
 
97
- # or get a single one by name
98
- coll = connect.collection("some_other_collection")
70
+ # Find out about its aliases, if any
71
+ cars_v2.alias? #=> false. It's a true collection
72
+ cars_v2.aliased? #=> true
73
+ cars_v2.aliases #=> [<SolrCloud::Alias "cars" (alias of "cars_v2")> ]
74
+ cars_v2.has_alias?("cars") #=> true
99
75
 
100
- mycoll.alive? # => true
101
- mycoll.healthy? #=> true. I'm not sure how these are different
76
+ cars_v2.delete! #=> SolrCloud::CollectionAliasedError: Collection 'cars_v2' can't be deleted; it's in use by aliases ["cars"]
102
77
 
103
- mycoll.alias? # false. It's a collection.
78
+ # Make a new collection
79
+ cars_v3 = server.create_collection(name: "cars_v3", configset: "cars_config")
80
+ cars_v3.aliased? #=> false
81
+ cars_v3.count #=> 0
82
+ cars_v3.configset #=> <SolrCloud::Configset 'cars_config' at http://localhost:8023>
104
83
 
105
- # Which configset is it based on?
106
- mycoll.configset #=> <SolrCloud::Configset '_default' at http://localhost:9999/>
84
+ # Work directly with an alias as if it's a collection
85
+ cars = server.get_collection("cars")
86
+ cars.alias? #=> true
87
+ cars.collection #=> <SolrCloud::Collection 'cars_v2' (aliased by 'cars')>
107
88
 
108
- # Sniff out and create aliases
109
- mycoll.aliases #=> [] None as of yet
110
- myalias = mycoll.alias_as("myalias")
89
+ # Make a new alias to v2
90
+ old_cars = cars_v2.alias_as("old_cars") #=> <SolrCloud::Alias "old_cars" (alias of "cars_v2")>
91
+ cars_v2.aliases #=> [<SolrCloud::Alias "cars" (alias of "cars_v2")>, <SolrCloud::Alias "old_cars" (alias of "cars_v2")>]
111
92
 
112
- mycoll.aliases #=> [<SolrCloud::Alias 'myalias' (alias of 'mycoll')>]
113
- mycoll.alias_names #=> ["myalias"]
93
+ # Now lets point the "cars" alias at cars_v3
94
+ cars.switch_collection_to cars_v3
114
95
 
115
- # Collection, Alias, and Configset can all access the underlying connection object
116
- # and call `get`, `post`, `put`, and `delete`
117
- mycoll.collection #=>
118
- mycoll.collection.get("path/from/connection/url", arg1: "One", arg2: "Two")
96
+ cars.collection.name #=> "cars_v3"
97
+ cars_v2.alias_names #=> ["old_cars"]
119
98
 
120
- # Try to delete the collection
121
- mycoll.delete! #=> SolrCloud::CollectionAliasedError: Collection 'mycoll' can't be deleted; it's in use by aliases ["myalias"]
122
- myalias.delete!
123
-
124
- mycoll.delete!
99
+ # cars_v1 isn't doing anything for us anymore. Ditch it.
100
+ cars_v1.delete!
125
101
 
126
102
  ```
127
103
 
128
- ### Aliases
129
-
130
- In all the important ways, aliases can be treated like collections. Here are the exceptions.
104
+ ## Documentation
131
105
 
132
- ```ruby
133
-
134
- # You can create an alias from the collection you're aliasing
135
- myalias = mycoll.alias_as("myalias")
136
-
137
- # Ask the connection object if it exists, and get it
138
- connect.alias?("myalias") #=> true
139
- myalias = connect.alias("myalias")
140
-
141
- # As this object if it's an alias, as opposed to a collection
142
- myalias.alias? #=> true
143
-
144
- # Set the collection this alias points to, removing its link from its existing collection
145
- myalias.collection = my_other_collection #=> sets myalias to point at my_other_collection
146
-
147
- myalias.delete!
148
- ```
106
+ Run `bundle exec rake docs` to generate the documentation in `docs/`
149
107
 
150
108
  ## Installation
151
109
 
@@ -168,4 +126,4 @@ This repository is set up to run tests under docker.
168
126
 
169
127
  ## Contributing
170
128
 
171
- Bug reports and pull requests are welcome on GitHub at https://github.com/mlibrary/solr_cloud-connect.
129
+ Bug reports and pull requests are welcome on GitHub at https://github.com/mlibrary/solr_cloud-connection.
data/Rakefile CHANGED
@@ -7,4 +7,19 @@ RSpec::Core::RakeTask.new(:spec)
7
7
 
8
8
  require "standard/rake"
9
9
 
10
- task default: %i[spec standard]
10
+ task default: %i[spec standard docs]
11
+ task docs: %i[yard]
12
+
13
+ require 'yard'
14
+
15
+ YARD::Rake::YardocTask.new do |t|
16
+ t.files = ["lib/**/*.rb"] # optional
17
+ t.options = [
18
+ "-mmarkdown",
19
+ "--embed-mixin", "SolrCloud::Connection::CollectionAdmin",
20
+ "--embed-mixin", "SolrCloud::Connection::ConfigsetAdmin",
21
+ "--embed-mixin", "SolrCloud::Connection::AliasAdmin",
22
+ "--hide-void-return"
23
+ ]
24
+ # t.stats_options = ["--list-undoc"] # optional
25
+ end
data/compose.yml CHANGED
@@ -9,13 +9,13 @@ services:
9
9
  - gem_cache:/gems
10
10
  env_file:
11
11
  - .env
12
- - env.development
12
+ - env.test
13
13
  command: "tail -f /dev/null"
14
14
 
15
15
  solr:
16
16
  build: spec/data/solr_docker/.
17
17
  ports:
18
- - "9999:8983"
18
+ - "8983:8983"
19
19
  environment:
20
20
  - ZK_HOST=zoo:2181
21
21
  depends_on:
@@ -1,4 +1,3 @@
1
1
  SOLR_URL="http://solr:8983"
2
2
  SOLR_PASSWORD=SolrRocks
3
3
  SOLR_USER=solr
4
- #
@@ -2,51 +2,58 @@
2
2
 
3
3
  module SolrCloud
4
4
  # An alias can mostly be just treated as a collection. It will identify itself as an alias if you
5
- # call #alias, and it can return and change the underlying collection it points to.
5
+ # call #alias?, and it can return and change the underlying collection it points to.
6
6
 
7
7
  # An alias shouldn't be created directly. Rather, get an existing one with
8
8
  # Connection#alias, or from a collection, or create one with
9
9
  # Collection#alias_as
10
10
  class Alias < Collection
11
11
  # An alias is, shockingly, an alias. Convenience to differentiate aliases from collections.
12
- # @see SolrCloud::Connection#alias?
12
+ # @see SolrCloud::Connection#get_alias?
13
13
  def alias?
14
14
  true
15
15
  end
16
16
 
17
- # Delete this alias
18
- # @return [SolrCloud::Connection]
17
+ # Delete this alias. Will be a no-op if it doesn't exist.
18
+ # @return [Connection] the connection
19
19
  def delete!
20
- coll = collection
21
- connection.delete_alias(name)
22
- coll
20
+ return connection unless exist?
21
+ connection.get("solr/admin/collections", action: "DELETEALIAS", name: name)
22
+ connection
23
+ end
24
+
25
+ # Does this alias still exist?
26
+ def exist?
27
+ connection.alias_names.include?(name)
23
28
  end
24
29
 
25
30
  # Get the collection this alias points to.
26
31
  # In real life, Solr will allow an alias to point to more than one collection. Functionality
27
32
  # for this might be added at some point
28
- # @return [SolrCloud::Collection]
33
+ # @return [Collection]
29
34
  def collection
30
- connection.collection_for_alias(name)
35
+ connection.alias_map[name].collection
31
36
  end
32
37
 
33
38
  # Redefine what collection this alias points to
34
39
  # This is equivalent to dropping/re-adding the alias, or calling connection.create_alias with `force: true`
35
40
  # @param coll [String, Collection] either the name of the collection, or a collection object itself
36
41
  # @return [Collection] the now-current collection
37
- def collection=(coll)
42
+ def switch_collection_to(coll)
38
43
  collect_name = case coll
39
- when String
40
- coll
41
- when Collection
42
- coll.name
43
- else
44
- raise "Alias#collection= only takes a name(string) or a collection, not '#{coll}'"
45
- end
46
- raise NoSuchCollectionError unless connection.collection?(collect_name)
44
+ when String
45
+ coll
46
+ when Collection
47
+ coll.name
48
+ else
49
+ raise "Alias#switch_collection_to only takes a name(string) or a collection, not '#{coll}'"
50
+ end
51
+ raise NoSuchCollectionError unless connection.has_collection?(collect_name)
47
52
  connection.create_alias(name: name, collection_name: collect_name, force: true)
48
53
  end
49
54
 
55
+ alias_method :collection=, :switch_collection_to
56
+
50
57
  # Get basic information on the underlying collection, so inherited methods that
51
58
  # use it (e.g., #healthy?) will work.
52
59
  # @overload info()
@@ -1,12 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "solr_cloud/connection"
4
+ require "forwardable"
4
5
 
5
6
  module SolrCloud
6
7
  # A Collection provides basic services on the collection -- checking its health,
7
8
  # creating or reporting aliases, and deleting itself.
8
9
  class Collection
9
- attr_reader :name, :connection
10
+
11
+ extend Forwardable
12
+
13
+ # Forward the HTTP verbs to the underlying connection
14
+
15
+ # @!method get
16
+ # Forwarded on to the underlying SolrCloud connection
17
+ # @see SolrCloud::Connection#get
18
+ def_delegator :@connection, :get
19
+
20
+ # @!method post
21
+ # Forwarded on to the underlying SolrCloud connection
22
+ # @see SolrCloud::Connection#post
23
+ def_delegator :@connection, :post
24
+
25
+ # @!method delete
26
+ # Forwarded on to the underlying SolrCloud connection
27
+ # @see SolrCloud::Connection#delete
28
+ def_delegator :@connection, :delete
29
+
30
+ # @!method put
31
+ # Forwarded on to the underlying SolrCloud connection
32
+ # @see SolrCloud::Connection#put
33
+ def_delegator :@connection, :put
34
+
35
+ # @return [SolrCloud::Connection] the underlying SolrCloud connection
36
+ attr_reader :name
37
+
38
+ # @return The name of the get_collection
39
+ attr_reader :connection
10
40
 
11
41
  # In general, users shouldn't use Collection.new; instead, use
12
42
  # connection.create_collection(name: "coll_name", configset: "existing_configset_name")
@@ -14,22 +44,28 @@ module SolrCloud
14
44
  # @param [String] name The name of the (already existing) collection
15
45
  # @param [SolrCloud::Connection] connection Connection to the solr "root" (http://blah:8888/)
16
46
  def initialize(name:, connection:)
17
- # raise NoSuchCollectionError.new("No collection #{name}") unless connection.collection?(name)
47
+ # raise NoSuchCollectionError.new("No collection #{name}") unless connection.has_collection?(name)
18
48
  @connection = connection.dup
19
49
  @name = name
20
50
  @sp = "/solr/#{name}"
21
51
  end
22
52
 
23
- # Delete this collection. Unlike the #delete_collection call on a Connection object,
24
- # for this one we throw an error if the collection isn't found, since that means
25
- # it was deleted via some other mechanism after this object was created and should probably be investigated.
26
- # @return [Connection] The underlying SolrCloud::Connection
53
+ # Delete this collection. Will no-op if the collection somehow doesn't still exist (because it was
54
+ # deleted via a different method, such as through the API)
55
+ # @return [Connection] The connection object used to create this collection object
27
56
  def delete!
28
- raise NoSuchCollectionError unless exist?
29
- connection.delete_collection(name)
57
+ return connection unless exist?
58
+ raise CollectionAliasedError.new("Cannot delete collection #{name}; it has alias(s) #{alias_names.join(", ")}") if aliased?
59
+ connection.get("solr/admin/collections", { action: "DELETE", name: name })
30
60
  connection
31
61
  end
32
62
 
63
+ # Does this collection still exist?
64
+ # @return [Boolean]
65
+ def exist?
66
+ connection.only_collection_names.include?(name)
67
+ end
68
+
33
69
  # Check to see if the collection is alive
34
70
  # @return [Boolean]
35
71
  def alive?
@@ -38,11 +74,9 @@ module SolrCloud
38
74
  false
39
75
  end
40
76
 
41
- alias_method :exist?, :alive?
42
-
43
77
  # Is this an alias?
44
78
  # Putting this in here breaks all sorts of isolation principles,
45
- # but being able to call #alias? on anything collection-like is
79
+ # but being able to call #get_alias? on anything collection-like is
46
80
  # convenient
47
81
  def alias?
48
82
  false
@@ -63,7 +97,7 @@ module SolrCloud
63
97
  # A (possibly empty) list of aliases targeting this collection
64
98
  # @return [Array<SolrCloud::Alias>] list of aliases that point to this collection
65
99
  def aliases
66
- connection.raw_alias_map.select { |a, c| c == name }.keys.map { |aname| Alias.new(name: aname, connection: connection) }
100
+ connection.alias_map.select { |_alias_name, ac| ac.collection.name == name }.values.map(&:alias)
67
101
  end
68
102
 
69
103
  # The names of the aliases that point to this collection
@@ -72,10 +106,26 @@ module SolrCloud
72
106
  aliases.map(&:name)
73
107
  end
74
108
 
109
+ # Does this collection have at least one alias?
110
+ # @return [Boolean] whether or not it has an alias
111
+ def aliased?
112
+ !aliases.empty?
113
+ end
114
+
115
+ # Do we have an alias of the given name?
75
116
  # Get a specific alias by name
76
- # @param aname [String] name of the alias
77
- def alias(aname)
78
- aliases.find {|a| a.name == aname} || (raise NoSuchAliasError.new("No alias named '#{aname}' pointing to collection #{name}"))
117
+ # @param alias_name [String] name of the alias
118
+ # @return [Boolean]
119
+ def has_alias?(alias_name)
120
+ alias_names.include?(alias_name)
121
+ end
122
+
123
+ # Get an alias that points to this collection by name, or nil if not found
124
+ # @param alias_name [String] name of the alias
125
+ # @return [Alias, nil] The alias object, or nil if not found
126
+ def get_alias(alias_name)
127
+ return nil unless has_alias?(alias_name)
128
+ connection.get_alias(alias_name)
79
129
  end
80
130
 
81
131
  # Create an alias for this collection. Always forces an overwrite unless you tell it not to
@@ -86,9 +136,6 @@ module SolrCloud
86
136
  connection.create_alias(name: alias_name, collection_name: name, force: true)
87
137
  end
88
138
 
89
- alias_method :alias_to, :alias_as
90
- alias_method :create_alias, :alias_as
91
-
92
139
  # Send a commit (soft if unspecified)
93
140
  # @return self
94
141
  def commit(hard: false)
@@ -106,13 +153,36 @@ module SolrCloud
106
153
  Configset.new(name: info["configName"], connection: connection)
107
154
  end
108
155
 
156
+ # Add a document or array of documents
157
+ # @todo Gotta check for errors and such!
158
+ # @param docs [Hash, Array<Hash>] One or more documents to add
159
+ # @return self
160
+
161
+ def add(docs)
162
+ docarray = if docs === Array
163
+ docs
164
+ else
165
+ [docs]
166
+ end
167
+ post("solr/#{name}/update/") do |r|
168
+ r.body = docarray
169
+ end
170
+ self
171
+ end
172
+
173
+ # Get a count of how many documents are in the index
174
+ # @return [Fixnum] the number of documents
175
+ def count
176
+ get("solr/#{name}/select", q: "*:*").body["response"]["numFound"]
177
+ end
178
+
109
179
  def inspect
110
180
  anames = alias_names
111
181
  astring = if anames.empty?
112
- ""
113
- else
114
- " (aliased by #{anames.map { |x| "'#{x}'" }.join(", ")})"
115
- end
182
+ ""
183
+ else
184
+ " (aliased by #{anames.map { |x| "'#{x}'" }.join(", ")})"
185
+ end
116
186
  "<#{self.class} '#{name}'#{astring}>"
117
187
  end
118
188
 
@@ -7,7 +7,12 @@ module SolrCloud
7
7
  # throw an error if that's an illegal operation (because a collection is
8
8
  # using it)
9
9
  class Configset
10
- attr_reader :name, :connection
10
+
11
+ # @return [String] the name of this configset
12
+ attr_reader :name
13
+
14
+ # @return [Connection] the connection object used to build this configset object
15
+ attr_reader :connection
11
16
 
12
17
  def initialize(name:, connection:)
13
18
  @name = name
@@ -15,11 +20,23 @@ module SolrCloud
15
20
  end
16
21
 
17
22
  # Delete this configset.
18
- # @see SolrCloud::Connection#delete_configset
23
+ # @see Connection#delete_configset
19
24
  # @return The underlying connection
20
25
  def delete!
21
- @connection.delete_configset(name)
22
- @connection
26
+ connection.delete_configset(name)
27
+ connection
28
+ end
29
+
30
+ # Which collections use this configset?
31
+ # @return [Array<Collection>] The collections defined to use this configset
32
+ def used_by
33
+ connection.only_collections.select { |coll| coll.configset.name == name }
34
+ end
35
+
36
+ # Are there any collections currently using this configset?
37
+ # @return [Boolean]
38
+ def in_use?
39
+ !used_by.empty?
23
40
  end
24
41
 
25
42
  def inspect
@@ -5,56 +5,41 @@ module SolrCloud
5
5
  # methods having to do with aliases, to be included by the connection object.
6
6
  # These are split out only to make it easier to deal with them.
7
7
  module AliasAdmin
8
+
9
+ # A simple data-class to pair an alias with its collection
8
10
  AliasCollectionPair = Struct.new(:alias, :collection)
9
11
 
10
- # Create an alias for the given collection name
11
- # @todo allow an alias to point to more than one collection?
12
+ # Create an alias for the given collection name.
13
+ #
14
+ # In general, prefer {Collection#alias_as} instead of
15
+ # running everything through the connection object.
12
16
  # @param name [String] Name of the new alias
13
17
  # @param collection_name [String] name of the collection
14
18
  # @param force [Boolean] whether to overwrite an existing alias
15
- # @raise [WontOverwriteError] if the alias exists and force isn't true
16
19
  # @raise [NoSuchCollectionError] if the collections isn't found
17
20
  # @return [Alias] the newly-created alias
18
21
  def create_alias(name:, collection_name:, force: false)
19
- raise NoSuchCollectionError.new("Can't find collection #{collection_name}") unless collection?(collection_name)
20
- if alias?(name) && !force
21
- raise WontOverwriteError.new("Alias '#{name}' already points to collection '#{self.alias(name).collection.name}'; won't overwrite without force: true")
22
+ unless legal_solr_name?(name)
23
+ raise IllegalNameError.new("'#{name}' is not a valid solr alias name. Use only ASCII letters/numbers, dash, and underscore")
24
+ end
25
+ raise NoSuchCollectionError.new("Can't find collection #{collection_name}") unless has_collection?(collection_name)
26
+ if has_alias?(name) && !force
27
+ raise WontOverwriteError.new("Alias '#{name}' already points to collection '#{self.get_alias(name).collection.name}'; won't overwrite without force: true")
22
28
  end
23
29
  connection.get("solr/admin/collections", action: "CREATEALIAS", name: name, collections: collection_name)
24
- SolrCloud::Alias.new(name: name, connection: self)
30
+ get_alias(name)
25
31
  end
26
32
 
27
33
  # Is there an alias with this name?
28
34
  # @return [Boolean]
29
- def alias?(name)
35
+ def has_alias?(name)
30
36
  alias_names.include? name
31
37
  end
32
38
 
33
- # Delete the alias
34
- # @param name [String] Name of the alias to delete
35
- # @return [SolrCloud::Connection]
36
- def delete_alias(name)
37
- connection.get("solr/admin/collections", action: "DELETEALIAS", name: name)
38
- end
39
-
40
- # The "raw" alias map, which just maps alias names to collection names
41
- # @return [Hash<String, String>]
42
- def raw_alias_map
43
- connection.get("solr/admin/collections", action: "LISTALIASES").body["aliases"]
44
- end
45
-
46
- # Get the aliases and create a map of the form
47
- # @return [Hash<String,Alias>] A hash mapping alias names to alias objects
48
- def alias_map
49
- raw_alias_map.keys.each_with_object({}) do |alias_name, h|
50
- h[alias_name] = SolrCloud::Alias.new(name: alias_name, connection: self)
51
- end
52
- end
53
-
54
39
  # List of alias objects
55
40
  # @return [Array<SolrCloud::Alias>] List of aliases
56
41
  def aliases
57
- alias_map.values
42
+ alias_map.values.map(&:alias)
58
43
  end
59
44
 
60
45
  # List of alias names
@@ -63,23 +48,40 @@ module SolrCloud
63
48
  alias_map.keys
64
49
  end
65
50
 
66
- # Get an alias object for the given name
51
+ # Get an alias object for the given name, erroring out if not found
52
+ # @param name [String] the name of the existing alias
53
+ # @return [Alias, nil] The alias if found, otherwise nil
54
+ def get_alias(name)
55
+ return nil unless has_alias?(name)
56
+ alias_map[name].alias
57
+ end
58
+
59
+ # Get an alias object for the given name, erroring out if not found
67
60
  # @param name [String] the name of the existing alias
68
61
  # @raise [SolrCloud::NoSuchAliasError] if it doesn't exist
69
62
  # @return [SolrCloud::Alias]
70
- def alias(name)
71
- am = alias_map
72
- raise NoSuchAliasError unless am[name]
73
- am[name]
63
+ def get_alias!(name)
64
+ raise NoSuchAliasError unless has_alias?(name)
65
+ get_alias(name)
74
66
  end
75
67
 
76
- # Get the collection associated with an alias
77
- # @param name [String] alias name
78
- # @return [Collection] collection associated with the alias
79
- def collection_for_alias(name)
80
- collname = connection.get("solr/admin/collections", action: "LISTALIASES").body["aliases"][name]
81
- Collection.new(name: collname, connection: self)
68
+ # Get the aliases and create a map of the form AliasName -> AliasObject
69
+ # @return [Hash<String,Alias>] A hash mapping alias names to alias objects
70
+ def alias_map
71
+ raw_alias_map.keys.each_with_object({}) do |alias_name, h|
72
+ a = Alias.new(name: alias_name, connection: self)
73
+ c = Collection.new(name: raw_alias_map[alias_name], connection: self)
74
+ h[alias_name] = AliasCollectionPair.new(a, c)
75
+ end
76
+ end
77
+
78
+ # The "raw" alias map, which just maps alias names to collection names
79
+ # @return [Hash<String, String>]
80
+ def raw_alias_map
81
+ connection.get("solr/admin/collections", action: "LISTALIASES").body["aliases"]
82
82
  end
83
83
  end
84
84
  end
85
85
  end
86
+
87
+
@@ -2,79 +2,98 @@
2
2
 
3
3
  module SolrCloud
4
4
  class Connection
5
- # methods having to do with connections, to be included by the connection object.
5
+ # methods having to do with collections, to be included by the connection object.
6
6
  # These are split out only to make it easier to deal with them.
7
+ #
8
+ # For almost everything in here, we treat aliases like collections -- calls to #collections,
9
+ # #has_collection?, #collection, etc. will respond to, and return, and alias if there is one.
10
+ # The idea is that you shouldn't need to know if something is an alias or a collection
11
+ # until it's relevant
7
12
  module CollectionAdmin
8
- # Create a new collection
13
+ # Create and return a new collection.
9
14
  # @param name [String] Name for the new collection
10
- # @param configset [String] name of the configset to use for this collection
11
- # @param version [String] A "version" which will be appended to the name following an underscore, if given.
12
- # Useful for testing and cronjobs.
15
+ # @param configset [String, Configset] (name of) the configset to use for this collection
13
16
  # @param shards [Integer]
14
17
  # @param replication_factor [Integer]
15
- # @todo Let version take symbols like :date and :datetime
18
+ # @raise [IllegalNameError]
16
19
  # @raise [NoSuchConfigSetError] if the named configset doesn't exist
17
20
  # @raise [WontOverwriteError] if the collection already exists
18
21
  # @return [Collection] the collection created
19
- def create_collection(name:, configset:, version: nil, shards: 1, replication_factor: 1)
20
- fullname = if version
21
- "#{name}_#{version}"
22
- else
23
- name
22
+ def create_collection(name:, configset:, shards: 1, replication_factor: 1)
23
+
24
+ unless legal_solr_name?(name)
25
+ raise IllegalNameError.new("'#{name}' is not a valid solr name. Use only ASCII letters/numbers, dash, and underscore")
24
26
  end
25
27
 
26
- raise WontOverwriteError.new("Collection #{fullname} already exists") if collection?(fullname)
27
- raise NoSuchConfigSetError.new("Configset '#{configset}' doesn't exist") unless configset?(configset)
28
+ configset_name = case configset
29
+ when Configset
30
+ configset.name
31
+ else
32
+ configset.to_s
33
+ end
34
+ raise WontOverwriteError.new("Collection #{name} already exists") if has_collection?(name)
35
+ raise NoSuchConfigSetError.new("Configset '#{configset_name}' doesn't exist") unless has_configset?(configset_name)
28
36
 
29
37
  args = {
30
38
  :action => "CREATE",
31
- :name => fullname,
39
+ :name => name,
32
40
  :numShards => shards,
33
41
  :replicationFactor => replication_factor,
34
- "collection.configName" => configset
42
+ "collection.configName" => configset_name
35
43
  }
36
44
  connection.get("solr/admin/collections", args)
37
- collection(name)
45
+ get_collection(name)
46
+ end
47
+
48
+ # Get a list of _only_ collections, as opposed to the mix of collections and aliases we
49
+ # usually do.
50
+ def only_collections
51
+ connection.get("api/collections").body["collections"].map { |c| Collection.new(name: c, connection: self) }
38
52
  end
39
53
 
40
- # Get a list of existing collections
41
- # @return [Array<SolrCloud::Collection>] possibly empty list of collection objects
54
+ # The names of only connections (and not aliases). Useful as a utility.
55
+ # @return [Array<String>] the names of the connections
56
+ def only_collection_names
57
+ only_collections.map(&:name)
58
+ end
59
+
60
+ # Get a list of collections (and aliases)
61
+ # @return [Array<Collection, Alias>] possibly empty list of collection and alias objects
42
62
  def collections
43
- collection_names.map { |coll| collection(coll) }
63
+ only_collections.union(aliases)
44
64
  end
45
65
 
46
- # A list of the names of existing collections
47
- # @return [Array<String>] the collection names, or empty array if there are none
66
+ # A list of the names of existing collections and aliases
67
+ # @return [Array<String>] the collection/alias names, or empty array if there are none
48
68
  def collection_names
49
- connection.get("api/collections").body["collections"]
69
+ collections.map(&:name)
50
70
  end
51
71
 
52
72
  # @param name [String] name of the collection to check on
53
73
  # @return [Boolean] Whether a collection with the passed name exists
54
- def collection?(name)
74
+ def has_collection?(name)
55
75
  collection_names.include? name
56
76
  end
57
77
 
58
- # Remove the configuration set with the given name. No-op if the
59
- # collection doesn't actually exist. Use #connection? manually if you need to raise on does-not-exist
60
- # @param [String,Symbol] name The name of the configuration set
61
- # @return [Connection] self
62
- def delete_collection(name)
63
- if collection? name
64
- connection.get("solr/admin/collections", {action: "DELETE", name: name})
78
+ # Get a collection object specifically for the named collection
79
+ # @param collection_name [String] name of the (already existing) collection
80
+ # @return [Collection, Alias, nil] The collection or alias if found, nil if not
81
+ def get_collection(collection_name)
82
+ return nil unless has_collection?(collection_name)
83
+ if only_collection_names.include?(collection_name)
84
+ Collection.new(name: collection_name, connection: self)
85
+ else
86
+ get_alias(collection_name)
65
87
  end
66
- self
67
- rescue Faraday::BadRequestError
68
- raise SolrCloud::CollectionAliasedError.new("Collection '#{name}' can't be deleted; it's in use by aliases #{collection(name).alias_names}")
69
88
  end
70
89
 
71
- # Get a connection object specifically for the named collection
90
+ # Get a connection/alias object, throwing an error if it's not found
72
91
  # @param collection_name [String] name of the (already existing) collection
73
- # @return [SolrCloud::Connection::Collection] The collection connection
74
- # @raise [NoSuchCollectionError] if the collection doesn't exist
75
- def collection(collection_name)
76
- raise NoSuchCollectionError.new("Collection '#{collection_name}' not found") unless collection?(collection_name)
77
- Collection.new(name: collection_name, connection: self)
92
+ # @return [Collection, Alias] The collection or alias
93
+ # @raise [NoSuchCollectionError] if the collection/alias doesn't exist
94
+ def get_collection!(collection_name)
95
+ raise NoSuchCollectionError.new("Collection '#{collection_name}' not found") unless has_collection?(collection_name)
96
+ get_collection(collection_name)
78
97
  end
79
98
  end
80
99
  end
@@ -7,6 +7,34 @@ module SolrCloud
7
7
  # methods having to do with configsets, to be included by the connection object.
8
8
  # These are split out only to make it easier to deal with them.
9
9
  module ConfigsetAdmin
10
+
11
+ # Given the path to a solr configuration "conf" directory (i.e., the one with
12
+ # solrconfig.xml in it), zip it up and send it to solr as a new configset.
13
+ # @param name [String] Name to give the new configset
14
+ # @param confdir [String, Pathname] Path to the solr configuration "conf" directory
15
+ # @param force [Boolean] Whether or not to overwrite an existing configset if there is one
16
+ # @raise [WontOverwriteError] if the configset already exists and "force" is false
17
+ # @return [Configset] the configset created
18
+ def create_configset(name:, confdir:, force: false)
19
+ config_set_name = name
20
+ unless legal_solr_name?(config_set_name)
21
+ raise IllegalNameError.new("'#{config_set_name}' is not a valid solr configset name. Use only ASCII letters/numbers, dash, and underscore")
22
+ end
23
+
24
+ if has_configset?(config_set_name) && !force
25
+ raise WontOverwriteError.new("Won't replace configset #{config_set_name} unless 'force: true' passed ")
26
+ end
27
+ zfile = "#{Dir.tmpdir}/solr_add_configset_#{name}_#{Time.now.hash}.zip"
28
+ z = ZipFileGenerator.new(confdir, zfile)
29
+ z.write
30
+ @connection.put("api/cluster/configs/#{config_set_name}") do |req|
31
+ req.body = File.binread(zfile)
32
+ end
33
+ # TODO: Error check in here somewhere
34
+ FileUtils.rm(zfile, force: true)
35
+ get_configset(name)
36
+ end
37
+
10
38
  # Get a list of the already-defined configSets
11
39
  # @return [Array<Configset>] possibly empty list of configSets
12
40
  def configsets
@@ -18,47 +46,29 @@ module SolrCloud
18
46
  connection.get("api/cluster/configs").body["configSets"]
19
47
  end
20
48
 
21
- alias_method :configurations, :configsets
22
-
23
49
  # Check to see if a configset is defined
24
50
  # @param name [String] Name of the configSet
25
51
  # @return [Boolean] Whether a configset with that name exists
26
- def configset?(name)
52
+ def has_configset?(name)
27
53
  configset_names.include? name.to_s
28
54
  end
29
55
 
30
- # Given the path to a solr configuration "conf" directory (i.e., the one with
31
- # solrconfig.xml in it), zip it up and send it to solr as a new configset.
32
- # @param name [String] Name to give the new configset
33
- # @param confdir [String, Pathname] Path to the solr configuration "conf" directory
34
- # @param force [Boolean] Whether or not to overwrite an existing configset if there is one
35
- # @param version [String] A "version" which will be appended to the name if given. Useful for
36
- # testing and cronjobs.
37
- # @raise [WontOverwriteError] if the configset already exists and "force" is false
38
- # @return [String] the name of the configset created
39
- def create_configset(name:, confdir:, force: false, version: "")
40
- config_set_name = name + version.to_s
41
- if configset?(config_set_name) && !force
42
- raise WontOverwriteError.new("Won't replace configset #{config_set_name} unless 'force: true' passed ")
43
- end
44
- zfile = "#{Dir.tmpdir}/solr_add_configset_#{name}_#{Time.now.hash}.zip"
45
- z = ZipFileGenerator.new(confdir, zfile)
46
- z.write
47
- @raw_connection.put("api/cluster/configs/#{config_set_name}") do |req|
48
- req.body = File.binread(zfile)
49
- end
50
- # TODO: Error check in here somewhere
51
- FileUtils.rm(zfile, force: true)
52
- config_set_name
56
+ # Get an existing configset
57
+ def get_configset(name)
58
+ Configset.new(name: name, connection: self)
53
59
  end
54
60
 
55
61
  # Remove the configuration set with the given name. No-op if the
56
- # configset doesn't actually exist. Use #configset? manually if you need to raise on does-not-exist
57
- # @param [String,Symbol] name The name of the configuration set
62
+ # configset doesn't actually exist. Test with {#has_configset?} and
63
+ # {Configset#in_use?} manually if need be.
64
+ #
65
+ # In general, prefer using {Configset#delete!} instead of running everything
66
+ # through the connection object.
67
+ # @param [String] name The name of the configuration set
58
68
  # @raise [InUseError] if the configset can't be deleted because it's in use by a live collection
59
69
  # @return [Connection] self
60
70
  def delete_configset(name)
61
- if configset? name
71
+ if has_configset? name
62
72
  connection.delete("api/cluster/configs/#{name}")
63
73
  end
64
74
  self
@@ -73,6 +83,8 @@ module SolrCloud
73
83
 
74
84
  # Pulled from the examples for rubyzip. No idea why it's not just a part
75
85
  # of the normal interface, but I guess I'm not one to judge.
86
+ #
87
+ # Code taken wholesale from https://github.com/rubyzip/rubyzip/blob/master/samples/example_recursive.rb
76
88
  class ZipFileGenerator
77
89
  # Initialize with the directory to zip and the location of the output archive.
78
90
  def initialize(input_dir, output_file)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module SolrCloud
4
4
  class Connection
5
- VERSION = "0.1.0"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
@@ -28,9 +28,36 @@ module SolrCloud
28
28
  include CollectionAdmin
29
29
  include AliasAdmin
30
30
 
31
- attr_reader :url, :logger, :raw_connection
31
+ # @return [String] String representation of the URL to solr
32
+ attr_reader :url
32
33
 
33
- def_delegators :@raw_connection, :get, :post, :delete, :put
34
+ # @return [#info] The logger
35
+ attr_reader :logger
36
+
37
+ # @return [Faraday::Connection] the underlying Faraday connection
38
+ attr_reader :connection
39
+
40
+ # let the underlying connection handle HTTP verbs
41
+
42
+ # @!method get
43
+ # Forwarded on to the underlying Faraday connection
44
+ # @see Faraday::Connection.get
45
+ def_delegator :@connection, :get
46
+
47
+ # @!method post
48
+ # Forwarded on to the underlying Faraday connection
49
+ # @see Faraday::Connection.post
50
+ def_delegator :@connection, :post
51
+
52
+ # @!method delete
53
+ # Forwarded on to the underlying Faraday connection
54
+ # @see Faraday::Connection.delete
55
+ def_delegator :@connection, :delete
56
+
57
+ # @!method put
58
+ # Forwarded on to the underlying Faraday connection
59
+ # @see Faraday::Connection.put
60
+ def_delegator :@connection, :put
34
61
 
35
62
  # Create a new connection to talk to solr
36
63
  # @param url [String] URL to the "root" of the solr installation. For a default solr setup, this will
@@ -38,21 +65,21 @@ module SolrCloud
38
65
  # @param user [String] username for basic auth, if you're using it
39
66
  # @param password [String] password for basic auth, if you're using it
40
67
  # @param logger [#info, :off, nil] An existing logger to pass in. The symbol ":off" means
41
- # don't do logging. If left undefined, will create a standard ruby logger to $stdout
68
+ # don't do logging. If left undefined, will create a standard ruby logger to $stdout
42
69
  # @param adapter [Symbol] The underlying http library to use within Faraday
43
70
  def initialize(url:, user: nil, password: nil, logger: nil, adapter: :httpx)
44
71
  @url = url
45
72
  @user = user
46
73
  @password = password
47
74
  @logger = case logger
48
- when :off, :none
49
- Logger.new(File::NULL, level: Logger::FATAL)
50
- when nil
51
- Logger.new($stderr, level: Logger::WARN)
52
- else
53
- logger
54
- end
55
- @raw_connection = create_raw_connection(url: url, adapter: adapter, user: user, password: password, logger: @logger)
75
+ when :off, :none
76
+ Logger.new(File::NULL, level: Logger::FATAL)
77
+ when nil
78
+ Logger.new($stderr, level: Logger::WARN)
79
+ else
80
+ logger
81
+ end
82
+ @connection = create_raw_connection(url: url, adapter: adapter, user: user, password: password, logger: @logger)
56
83
  bail_if_incompatible!
57
84
  @logger.info("Connected to supported solr at #{url}")
58
85
  end
@@ -61,7 +88,7 @@ module SolrCloud
61
88
  # @param faraday_connection [Faraday::Connection] A pre-build faraday connection object
62
89
  def self.new_from_faraday(faraday_connection)
63
90
  c = allocate
64
- c.instance_variable_set(:@raw_connection, faraday_connection)
91
+ c.instance_variable_set(:@connection, faraday_connection)
65
92
  c.instance_variable_set(:@url, faraday_connection.build_url.to_s)
66
93
  c
67
94
  end
@@ -69,7 +96,7 @@ module SolrCloud
69
96
  # Create a Faraday connection object to base the API client off of
70
97
  # @see #initialize
71
98
  def create_raw_connection(url:, adapter: :httpx, user: nil, password: nil, logger: nil)
72
- Faraday.new(request: {params_encoder: Faraday::FlatParamsEncoder}, url: URI(url)) do |faraday|
99
+ Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }, url: URI(url)) do |faraday|
73
100
  faraday.use Faraday::Response::RaiseError
74
101
  faraday.request :url_encoded
75
102
  if user
@@ -87,7 +114,7 @@ module SolrCloud
87
114
 
88
115
  # Allow accessing the raw_connection via "connection". Yes, connection.connection
89
116
  # can be confusing, but it makes the *_admin stuff easier to read.
90
- alias_method :connection, :raw_connection
117
+ alias_method :connection, :connection
91
118
 
92
119
  # Check to see if we can actually talk to the solr in question
93
120
  # raise [UnsupportedSolr] if the solr version isn't at least 8
@@ -145,6 +172,15 @@ module SolrCloud
145
172
  _version_part_int(2)
146
173
  end
147
174
 
175
+ # Check to see if the given string follows solr's rules for thing
176
+ # Solr only allows ASCII letters and numbers, underscore, and dash,
177
+ # and it can't start with an underscore.
178
+ # @param str [String] string to check
179
+ # @return [Boolean]
180
+ def legal_solr_name?(str)
181
+ !(/[^a-zA-Z_\-0-9]/.match?(str) or str.start_with?("_"))
182
+ end
183
+
148
184
  def inspect
149
185
  "<#{self.class} #{@url}>"
150
186
  end
@@ -156,3 +192,5 @@ module SolrCloud
156
192
  end
157
193
  end
158
194
  end
195
+
196
+
@@ -19,4 +19,6 @@ module SolrCloud
19
19
  class Unauthorized < ArgumentError; end
20
20
 
21
21
  class ConnectionFailed < RuntimeError; end
22
+
23
+ class IllegalNameError < ArgumentError; end
22
24
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solr_cloud-connection
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bill Dueber
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-30 00:00:00.000000000 Z
11
+ date: 2023-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: yard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description:
112
126
  email:
113
127
  - bill@dueber.com
@@ -115,7 +129,7 @@ executables: []
115
129
  extensions: []
116
130
  extra_rdoc_files: []
117
131
  files:
118
- - ".env.local"
132
+ - ".env.github"
119
133
  - ".rspec"
120
134
  - ".standard.yml"
121
135
  - CHANGELOG.md
@@ -124,7 +138,7 @@ files:
124
138
  - README.md
125
139
  - Rakefile
126
140
  - compose.yml
127
- - env.development
141
+ - env.test
128
142
  - lib/solr_cloud/alias.rb
129
143
  - lib/solr_cloud/collection.rb
130
144
  - lib/solr_cloud/configset.rb