optica-client 0.1.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 +7 -0
- data/.gitignore +9 -0
- data/Gemfile +2 -0
- data/README.md +47 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/optical +4 -0
- data/lib/optica/client/cli.rb +290 -0
- data/lib/optica/client/config.rb +45 -0
- data/lib/optica/client/fetch_json.rb +39 -0
- data/lib/optica/client/request.rb +120 -0
- data/lib/optica/client/version.rb +5 -0
- data/lib/optica/client.rb +12 -0
- data/optica-client.gemspec +37 -0
- metadata +143 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2707b665c02b7e9fab50ed54997fcd7f6deaba82
|
4
|
+
data.tar.gz: 6a1e0236dd17a745341c62fb12723a325ad89a78
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f1011f391dd4695e3ebd5bc5833697d34e785d93b3510ff13fcd35c936731a4c9800b9a76cd4a2d7512620f2fbd8c2d9cedfe56a7bec06353b1fab1c69d5d759
|
7
|
+
data.tar.gz: 5be5f02624481514824262fd12fbde9d21287623996ee43d1f94d8526a60d0f3bb0f43653e516ed5e44bd90469203f367124f3f7e8314f73a0bb5f716d855522
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# optica-client
|
2
|
+
|
3
|
+
This `optica-client` is a CLI for Airbnb's [Optica](https://github.com/airbnb/optica) service.
|
4
|
+
It's command-line name is `optical`.
|
5
|
+
|
6
|
+
This is not an official Airbnb product.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Install it via Rubygems:
|
11
|
+
|
12
|
+
$ gem install optica-client
|
13
|
+
|
14
|
+
You'll want to configure the command-line client to use your Optica instance:
|
15
|
+
|
16
|
+
$ optical -H https://optica.example.com
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
```text
|
21
|
+
Usage: optical [options] [FIELD=FILTER] [FIELD2=FILTER2...]
|
22
|
+
|
23
|
+
Fetch host information from Optica, and cache it for 15 minutes. Output the
|
24
|
+
fetched information as single-line JSON hashes, suitable for furhter processing with `jq`.
|
25
|
+
|
26
|
+
FIELD: any optica field; see your optica host for availible fields
|
27
|
+
FILTER: either a bare string, like "optica", or a regex string, like "/^(o|O)ptica?/"
|
28
|
+
|
29
|
+
Options:
|
30
|
+
-s, --select a,b,c Retrieve the given fields, in addition to the defaults
|
31
|
+
-a, --all Retrieve all fields (default is just role,id,hostname)
|
32
|
+
-v, --verbose Print debug information to STDERR
|
33
|
+
-p, --pretty[=true] Pretty-print JSON (default true when STDOUT is a TTY)
|
34
|
+
-r, --refresh Delete cache before performing request.
|
35
|
+
-h, --host URI Optica host (default "https://optica.d.musta.ch")
|
36
|
+
-H, --set-default-host URI Set the default optica host
|
37
|
+
```
|
38
|
+
|
39
|
+
## Development
|
40
|
+
|
41
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
42
|
+
|
43
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
44
|
+
|
45
|
+
## Contributing
|
46
|
+
|
47
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/justjake/optica-client.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "optical"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "pry"
|
14
|
+
Pry.start
|
data/bin/setup
ADDED
data/exe/optical
ADDED
@@ -0,0 +1,290 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'filecache'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
require_relative './config'
|
6
|
+
require_relative './request'
|
7
|
+
require_relative './fetch_json'
|
8
|
+
|
9
|
+
module Optica
|
10
|
+
module Client
|
11
|
+
# Command-line interface
|
12
|
+
class CLI
|
13
|
+
# rate-limit when printing huge JSON to a tty
|
14
|
+
TTY_TIMEOUT = 0.00001
|
15
|
+
|
16
|
+
USER_PATH = Pathname.new('~/.optical').expand_path
|
17
|
+
CONFIG_PATH = USER_PATH.join('config.yml')
|
18
|
+
CACHE_ROOT = USER_PATH.join('cache').to_s
|
19
|
+
|
20
|
+
ERR_NOT_FOUND = 4
|
21
|
+
ERR_INVALID = 2
|
22
|
+
|
23
|
+
# 15 min
|
24
|
+
CACHE_MAX_AGE = 15 * 60
|
25
|
+
|
26
|
+
def self.run(argv)
|
27
|
+
new.run(argv)
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :fields, :verbose, :cache, :delete_cache
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@config = ::Optica::Client::Config.from_file(CONFIG_PATH)
|
34
|
+
@host = nil
|
35
|
+
@fields = []
|
36
|
+
@verbose = false
|
37
|
+
@pretty = data_pipe.tty?
|
38
|
+
@cache = ::FileCache.new(
|
39
|
+
"requests",
|
40
|
+
CACHE_ROOT,
|
41
|
+
CACHE_MAX_AGE,
|
42
|
+
1
|
43
|
+
)
|
44
|
+
@delete_cache = false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Options for the CLI
|
48
|
+
#
|
49
|
+
# @return [OptionParser]
|
50
|
+
def option_parser
|
51
|
+
@option_parser ||= OptionParser.new do |o|
|
52
|
+
o.banner = "Usage: optical [options] [FIELD=FILTER] [FIELD2=FILTER2...]"
|
53
|
+
|
54
|
+
o.separator ''
|
55
|
+
o.separator <<-EOS
|
56
|
+
Fetch host information from Optica, and cache it for 15 minutes. Output the
|
57
|
+
fetched information as single-line JSON hashes, suitable for furhter processing with `jq`.
|
58
|
+
|
59
|
+
FIELD: any optica field; see your optica host for availible fields
|
60
|
+
FILTER: either a bare string, like "optica", or a regex string, like "/^(o|O)ptica?/"
|
61
|
+
EOS
|
62
|
+
|
63
|
+
o.separator ''
|
64
|
+
o.separator 'Options:'
|
65
|
+
|
66
|
+
o.on(
|
67
|
+
'-s',
|
68
|
+
'--select a,b,c',
|
69
|
+
::Array,
|
70
|
+
'Retrieve the given fields, in addition to the defaults'
|
71
|
+
) do |fs|
|
72
|
+
@fields.concat(fs)
|
73
|
+
end
|
74
|
+
|
75
|
+
o.on(
|
76
|
+
'-a',
|
77
|
+
'--all',
|
78
|
+
'Retrieve all fields (default is just role,id,hostname)'
|
79
|
+
) do |all|
|
80
|
+
@fields = nil if all
|
81
|
+
end
|
82
|
+
|
83
|
+
o.on(
|
84
|
+
'-v',
|
85
|
+
'--verbose',
|
86
|
+
'Print debug information to STDERR'
|
87
|
+
) do |v|
|
88
|
+
@verbose = v
|
89
|
+
end
|
90
|
+
|
91
|
+
o.on('-p', "--pretty[=#{data_pipe.tty?}]", "Pretty-print JSON (default true when STDOUT is a TTY)") do |p|
|
92
|
+
@pretty = p
|
93
|
+
end
|
94
|
+
|
95
|
+
o.on(
|
96
|
+
'-r',
|
97
|
+
'--refresh',
|
98
|
+
'Delete cache before performing request.'
|
99
|
+
) do |r|
|
100
|
+
@delete_cache = r
|
101
|
+
end
|
102
|
+
|
103
|
+
o.on(
|
104
|
+
'-h',
|
105
|
+
'--host URI',
|
106
|
+
"Optica host (default #{@config.default_host.inspect})"
|
107
|
+
) do |host|
|
108
|
+
@host = host
|
109
|
+
end
|
110
|
+
|
111
|
+
o.on(
|
112
|
+
'-H URI',
|
113
|
+
'--set-default-host URI',
|
114
|
+
'Set the default optica host'
|
115
|
+
) do |h|
|
116
|
+
# TODO: move to #run
|
117
|
+
@host = h
|
118
|
+
@config.default_host = h
|
119
|
+
@config.write!
|
120
|
+
log "set default host to #{h}"
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Run the CLI
|
127
|
+
#
|
128
|
+
# @param [Array<String>] argv Command-line args
|
129
|
+
def run(argv)
|
130
|
+
args = option_parser.parse(argv)
|
131
|
+
|
132
|
+
begin
|
133
|
+
filters = args.map { |arg| parse_filter(arg) }.reduce({}, :merge)
|
134
|
+
rescue ArgumentError => err
|
135
|
+
ui_pipe.puts err.message
|
136
|
+
ui_pipe.puts ''
|
137
|
+
ui_pipe.puts option_parser
|
138
|
+
return ERR_INVALID
|
139
|
+
end
|
140
|
+
|
141
|
+
if host.nil?
|
142
|
+
ui_pipe.puts 'No host given.'
|
143
|
+
ui_pipe.puts 'Set the default with -H, or for the invocation with -h.'
|
144
|
+
ui_pipe.puts ''
|
145
|
+
ui_pipe.puts option_parser
|
146
|
+
return ERR_INVALID
|
147
|
+
end
|
148
|
+
|
149
|
+
manage_cache
|
150
|
+
|
151
|
+
req = ::Optica::Client::Request.new(host).where(filters)
|
152
|
+
if fields
|
153
|
+
req.select(*fields)
|
154
|
+
else
|
155
|
+
req.select_all
|
156
|
+
end
|
157
|
+
|
158
|
+
json = fetch(req)
|
159
|
+
output(json['nodes'])
|
160
|
+
|
161
|
+
if json['nodes'].any?
|
162
|
+
# happy!
|
163
|
+
return 0
|
164
|
+
else
|
165
|
+
# none found
|
166
|
+
return ERR_NOT_FOUND
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def fetch(req)
|
171
|
+
log "URL: #{req.root}"
|
172
|
+
log "Filters: #{req.filters}"
|
173
|
+
log "Fields: #{req.select_all? ? '(all fields)' : req.fields.inspect}"
|
174
|
+
log "GET #{req.to_uri}"
|
175
|
+
|
176
|
+
key = req.to_uri.to_s
|
177
|
+
cache.get_or_set(key) do
|
178
|
+
fetch_with_progress_bar(req.to_uri)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def output(json)
|
183
|
+
log "got #{json.size} entries"
|
184
|
+
|
185
|
+
use_sleep = false
|
186
|
+
if json.size >= 1000 && data_pipe.tty?
|
187
|
+
log 'reducing output speed to allow Ctrl-C'
|
188
|
+
use_sleep = true
|
189
|
+
end
|
190
|
+
|
191
|
+
json.each do |_ip, node|
|
192
|
+
string = @pretty ? JSON.pretty_generate(node) : JSON.fast_generate(node)
|
193
|
+
data_pipe.puts string
|
194
|
+
# easier Ctrl-C in Tmux
|
195
|
+
sleep TTY_TIMEOUT if use_sleep
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def manage_cache
|
200
|
+
# clean up expired stuff
|
201
|
+
cache.purge
|
202
|
+
|
203
|
+
if delete_cache
|
204
|
+
log "deleting cache dir #{CACHE_ROOT}"
|
205
|
+
FileUtils.rm_r(CACHE_ROOT)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def fetch_with_progress_bar(uri)
|
210
|
+
::Optica::Client.fetch_json(uri) do |_chunk, ratio|
|
211
|
+
view = "Download #{progress_bar(ratio)}"
|
212
|
+
|
213
|
+
ui_pipe.print "\r#{view}"
|
214
|
+
ui_pipe.print "\n" if ratio == 1.0
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# Returns a progress bar, as a string.
|
219
|
+
#
|
220
|
+
# Looks kinda like this:
|
221
|
+
# [>>>>> ] NN.NN%
|
222
|
+
#
|
223
|
+
# @return [String]
|
224
|
+
def progress_bar(ratio)
|
225
|
+
width = 40
|
226
|
+
chars = (width * ratio).to_i
|
227
|
+
start = '['
|
228
|
+
fin = ']'
|
229
|
+
done = '>' * chars
|
230
|
+
to_do = ' ' * (width - chars)
|
231
|
+
percent = format(' %.2f%', ratio * 100)
|
232
|
+
start + done + to_do + fin + percent
|
233
|
+
end
|
234
|
+
|
235
|
+
# Parse a command-line argument into a single Optica filter.
|
236
|
+
#
|
237
|
+
# Filter types:
|
238
|
+
# - exact string match: base case
|
239
|
+
# attribute=string
|
240
|
+
#
|
241
|
+
# - regex match: filter begins and ends with /
|
242
|
+
# attribute=/^[rR]egexp?/
|
243
|
+
#
|
244
|
+
# - array match: begins with [, ends with ]
|
245
|
+
# attribute=[one,two]
|
246
|
+
#
|
247
|
+
# @param string [String]
|
248
|
+
# @return [Hash<String, Any>] a filter hash
|
249
|
+
def parse_filter(string)
|
250
|
+
unless string.include?('=')
|
251
|
+
raise ArgumentError.new("Invalid filter: #{string.inspect}")
|
252
|
+
end
|
253
|
+
|
254
|
+
key, *values = string.split('=')
|
255
|
+
value = values.join('=')
|
256
|
+
|
257
|
+
# parse regex
|
258
|
+
if value[0] == '/' && value[-1] == '/'
|
259
|
+
return { key => /#{value[1...-1]}/ }
|
260
|
+
end
|
261
|
+
|
262
|
+
# parse array-like
|
263
|
+
if value[0] == '[' && value[-1] == ']'
|
264
|
+
return { key => value[1...-1].split(',') }
|
265
|
+
end
|
266
|
+
|
267
|
+
# just a string
|
268
|
+
{ key => value }
|
269
|
+
end
|
270
|
+
|
271
|
+
def host
|
272
|
+
@host || @config.default_host
|
273
|
+
end
|
274
|
+
|
275
|
+
def log(msg)
|
276
|
+
if verbose
|
277
|
+
ui_pipe.puts(msg)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def data_pipe
|
282
|
+
$stdout
|
283
|
+
end
|
284
|
+
|
285
|
+
def ui_pipe
|
286
|
+
$stderr
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Optica
|
4
|
+
module Client
|
5
|
+
# Handles storing and loading configurable settings for our CLI
|
6
|
+
class Config
|
7
|
+
attr_accessor :config_path
|
8
|
+
attr_accessor :default_host
|
9
|
+
|
10
|
+
def self.from_file(path)
|
11
|
+
new(config_path: path.to_s).reload
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(hash = {})
|
15
|
+
set_all(hash)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_h
|
19
|
+
{
|
20
|
+
config_path: config_path.to_s,
|
21
|
+
default_host: default_host.to_s,
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def write!
|
26
|
+
data = YAML.dump(to_h)
|
27
|
+
File.write(config_path, data)
|
28
|
+
end
|
29
|
+
|
30
|
+
def reload
|
31
|
+
return self unless File.exist?(config_path)
|
32
|
+
|
33
|
+
data = YAML.load(File.read(config_path)).merge(config_path: config_path)
|
34
|
+
set_all(data)
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_all(data)
|
39
|
+
data.each do |key, val|
|
40
|
+
self.public_send("#{key}=", val)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
module Optica
|
6
|
+
module Client
|
7
|
+
# Fetch the JSON data at the given URI. Blocks.
|
8
|
+
#
|
9
|
+
# As data is received, yeilds the data chunk (a string) and the completion
|
10
|
+
# ratio (a float).
|
11
|
+
#
|
12
|
+
# @return [Any] the parsed JSON
|
13
|
+
def self.fetch_json(uri)
|
14
|
+
io = StringIO.new
|
15
|
+
|
16
|
+
Net::HTTP.start(
|
17
|
+
uri.host,
|
18
|
+
uri.port,
|
19
|
+
use_ssl: uri.scheme == 'https'
|
20
|
+
) do |http|
|
21
|
+
req = Net::HTTP::Get.new(uri)
|
22
|
+
|
23
|
+
http.request(req) do |res|
|
24
|
+
file_size = res['content-length'].to_i
|
25
|
+
downloaded = 0.0
|
26
|
+
|
27
|
+
res.read_body do |chunk|
|
28
|
+
io.write chunk
|
29
|
+
downloaded += chunk.size
|
30
|
+
ratio = downloaded / file_size
|
31
|
+
yield(chunk, ratio) if block_given?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
JSON.parse(io.string)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Optica
|
4
|
+
module Client
|
5
|
+
# Request builds URIs to fetch data from Optica. There is no planned support
|
6
|
+
# for posting data to Optica.
|
7
|
+
#
|
8
|
+
# By default a Request will request the minimum number of fields from Optica
|
9
|
+
# to save on response size, using the /roles endpoint. Use the {#fields} or
|
10
|
+
# {#all_fields!} methods to fetch more fields.
|
11
|
+
#
|
12
|
+
# Build your request, then submit it using your HTTP client of choice using
|
13
|
+
# the {#to_uri} method.
|
14
|
+
class Request
|
15
|
+
# @param root_url [String] HTTP(S) URI root of your Optica instance.
|
16
|
+
# @param given_opts [Hash] options
|
17
|
+
# @option given_opts [Array<String>] :fields Additional fields to request.
|
18
|
+
# see also {#fields} and {#all_fields!}
|
19
|
+
# @option given_opts [Hash] :filters Filters. See {#where}.
|
20
|
+
# @option given_opts [Boolean] :all_fields (false) See {#all_fields!}
|
21
|
+
def initialize(root_url, given_opts = {})
|
22
|
+
opts = {
|
23
|
+
fields: [],
|
24
|
+
filters: {},
|
25
|
+
all_fields: false,
|
26
|
+
}.merge(given_opts)
|
27
|
+
|
28
|
+
@uri = URI(root_url)
|
29
|
+
@fields = opts[:fields]
|
30
|
+
@filters = opts[:filters]
|
31
|
+
@all_fields = opts[:all_fields]
|
32
|
+
end
|
33
|
+
|
34
|
+
def filters
|
35
|
+
@filters.dup
|
36
|
+
end
|
37
|
+
|
38
|
+
def fields
|
39
|
+
@fields.dup
|
40
|
+
end
|
41
|
+
|
42
|
+
# returns the fields that will be fetched using this request, via the
|
43
|
+
# /roles endpoint.
|
44
|
+
#
|
45
|
+
# @see https://github.com/airbnb/optica/blob/master/optica.rb#L15-L24
|
46
|
+
|
47
|
+
# Add more requested fields.
|
48
|
+
#
|
49
|
+
# @param fields [Array<String>]
|
50
|
+
# @return self
|
51
|
+
def select(*fields)
|
52
|
+
@fields.concat(fields).uniq!
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
# Request all fields. Overwrites any previously-requested fields.
|
57
|
+
#
|
58
|
+
# @return self
|
59
|
+
def select_all
|
60
|
+
@all_fields = true
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
# Add filters to this optica request
|
65
|
+
#
|
66
|
+
# Filters should be a hash of String => Constraint, where constraint is a
|
67
|
+
# - regex (regex match)
|
68
|
+
# - boolean (matches 1, true, or True)
|
69
|
+
# - string (exact match)
|
70
|
+
#
|
71
|
+
# @param filters [Hash]
|
72
|
+
# @return self
|
73
|
+
def where(filters)
|
74
|
+
@filters.merge!(filters)
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
# @return [URI]
|
79
|
+
def to_uri
|
80
|
+
uri = @uri.dup
|
81
|
+
uri.query = URI.encode_www_form(query_params)
|
82
|
+
uri.path = '/roles' unless @all_fields
|
83
|
+
uri
|
84
|
+
end
|
85
|
+
|
86
|
+
def root
|
87
|
+
@uri
|
88
|
+
end
|
89
|
+
|
90
|
+
def select_all?
|
91
|
+
@all_fields
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# @return [String]
|
97
|
+
def query_params
|
98
|
+
params = {}
|
99
|
+
@filters.each do |key, value|
|
100
|
+
params[key.to_s] = filter_to_param(value)
|
101
|
+
end
|
102
|
+
if @fields.any? && !@all_fields
|
103
|
+
params['_extra_fields'] = @fields.join(',')
|
104
|
+
end
|
105
|
+
params
|
106
|
+
end
|
107
|
+
|
108
|
+
# @return [String]
|
109
|
+
def filter_to_param(value)
|
110
|
+
case value
|
111
|
+
when ::Regexp
|
112
|
+
value.source
|
113
|
+
else
|
114
|
+
literal = ::Regexp.escape(value.to_s)
|
115
|
+
"^#{literal}$"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
##
|
2
|
+
# Optica::Client helps you efficiently query Optica, Airbnb's open-source host
|
3
|
+
# registration service.
|
4
|
+
#
|
5
|
+
# @see Optica::Client::Request
|
6
|
+
|
7
|
+
module Optica
|
8
|
+
module Client
|
9
|
+
require_relative './client/version'
|
10
|
+
require_relative './client/request'
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'optica/client/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "optica-client"
|
8
|
+
spec.version = Optica::Client::VERSION
|
9
|
+
spec.authors = ["Jake Teton-Landis"]
|
10
|
+
spec.email = ["jake.tl@airbnb.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{An Optica client}
|
13
|
+
spec.description = %q{An efficient Optica CLI client and accompanying Ruby library}
|
14
|
+
spec.homepage = "https://github.com/justjake/optica-client"
|
15
|
+
|
16
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
17
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
18
|
+
if spec.respond_to?(:metadata)
|
19
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
20
|
+
end
|
21
|
+
|
22
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
23
|
+
f.match(%r{^(test|spec|features)/})
|
24
|
+
end
|
25
|
+
spec.bindir = "exe"
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
|
29
|
+
spec.add_dependency "filecache", "~> 1.0.2"
|
30
|
+
|
31
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
32
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
33
|
+
|
34
|
+
spec.add_development_dependency "pry"
|
35
|
+
spec.add_development_dependency "pry-byebug"
|
36
|
+
spec.add_development_dependency "pry-doc"
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: optica-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jake Teton-Landis
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-04-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: filecache
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.14'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.14'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry-byebug
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry-doc
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: An efficient Optica CLI client and accompanying Ruby library
|
98
|
+
email:
|
99
|
+
- jake.tl@airbnb.com
|
100
|
+
executables:
|
101
|
+
- optical
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- .gitignore
|
106
|
+
- Gemfile
|
107
|
+
- README.md
|
108
|
+
- Rakefile
|
109
|
+
- bin/console
|
110
|
+
- bin/setup
|
111
|
+
- exe/optical
|
112
|
+
- lib/optica/client.rb
|
113
|
+
- lib/optica/client/cli.rb
|
114
|
+
- lib/optica/client/config.rb
|
115
|
+
- lib/optica/client/fetch_json.rb
|
116
|
+
- lib/optica/client/request.rb
|
117
|
+
- lib/optica/client/version.rb
|
118
|
+
- optica-client.gemspec
|
119
|
+
homepage: https://github.com/justjake/optica-client
|
120
|
+
licenses: []
|
121
|
+
metadata:
|
122
|
+
allowed_push_host: https://rubygems.org
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - '>='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
requirements: []
|
138
|
+
rubyforge_project:
|
139
|
+
rubygems_version: 2.6.10
|
140
|
+
signing_key:
|
141
|
+
specification_version: 4
|
142
|
+
summary: An Optica client
|
143
|
+
test_files: []
|