solr_cloud-connection 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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