bkblz 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/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.rb +141 -0
- data/Rakefile +11 -0
- data/bkblz.gemspec +25 -0
- data/lib/all.rb +6 -0
- data/lib/bkblz.rb +35 -0
- data/lib/bkblz/config.rb +35 -0
- data/lib/bkblz/core_ext.rb +22 -0
- data/lib/bkblz/logger.rb +139 -0
- data/lib/bkblz/map_key_formatter.rb +21 -0
- data/lib/bkblz/v1/all.rb +16 -0
- data/lib/bkblz/v1/authorize_account.rb +24 -0
- data/lib/bkblz/v1/create_bucket.rb +22 -0
- data/lib/bkblz/v1/delete_bucket.rb +23 -0
- data/lib/bkblz/v1/delete_file_version.rb +23 -0
- data/lib/bkblz/v1/error_response.rb +24 -0
- data/lib/bkblz/v1/get_upload_url.rb +22 -0
- data/lib/bkblz/v1/list_buckets.rb +18 -0
- data/lib/bkblz/v1/list_file_versions.rb +43 -0
- data/lib/bkblz/v1/model_base.rb +37 -0
- data/lib/bkblz/v1/models.rb +29 -0
- data/lib/bkblz/v1/request.rb +81 -0
- data/lib/bkblz/v1/response.rb +114 -0
- data/lib/bkblz/v1/session.rb +72 -0
- data/lib/bkblz/v1/upload_file.rb +50 -0
- data/lib/bkblz/version.rb +3 -0
- metadata +116 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7636a95e10db31242f5b3e666734c62e16f870da
|
4
|
+
data.tar.gz: 54425688a09f9dcec3d598ad9b9fc312e1cb8c42
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 73aa799368884833b533d5ae3e8f23f7dd3b4c0a8aa0126c69509420520b290bb631721860b788a66ab0d2b13839b27fcb68e064ad07adb635285234ac932eca
|
7
|
+
data.tar.gz: ba3359e74fc5b8e49da7f21ebd60a8f5e59d4ee421633a22dbd0d71428455120f16b294b72e7d012c467eac147832dddc1cbefca3e4287e9024f25fad22e5c54
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Erick Johnson
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
$: << 'lib'
|
2
|
+
require 'all'
|
3
|
+
|
4
|
+
# Run `ruby README.rb` for a working demo, but first add your
|
5
|
+
# applicatoin key and account id in the slots below.
|
6
|
+
Bkblz.configure do |config_map|
|
7
|
+
config_map.merge!(
|
8
|
+
:application_key => "!!! APP KEY !!!",
|
9
|
+
:account_id => "!!! ACCOUNT ID !!!",
|
10
|
+
:debug_http => false,
|
11
|
+
:log_level => :info # change this to :debug for more info
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
Bkblz.log.info do <<EOS
|
16
|
+
# Step 1, the block above configures some defaults (including the
|
17
|
+
# logger, which is why this is after the configure block), see
|
18
|
+
# Bkblz::Config for details. This is where to set the account_id
|
19
|
+
# and application_key.
|
20
|
+
EOS
|
21
|
+
end
|
22
|
+
|
23
|
+
if Bkblz.config.account_id.match /!!!/
|
24
|
+
Bkblz.log.error "you didn't fill in your credentials, read the comments"
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
|
28
|
+
Bkblz.log.info do <<EOS
|
29
|
+
# Step 2, using the config above, create an authorized session. All
|
30
|
+
# requests will run in the context of this session. See
|
31
|
+
# +Bkblz::V1::Session#authorize+.
|
32
|
+
EOS
|
33
|
+
end
|
34
|
+
Bkblz::V1::Session.authorize Bkblz.config do |api_session|
|
35
|
+
Bkblz.log.info "API session => #{api_session}"
|
36
|
+
|
37
|
+
Bkblz.log.info do <<EOS
|
38
|
+
# Step 3, first try to find an existing bucket named my-test-bucket,
|
39
|
+
# we'll use that if it exists. All requests in a session are sent
|
40
|
+
# through the session so that the request object gets access to the
|
41
|
+
# auth credentials.
|
42
|
+
EOS
|
43
|
+
end
|
44
|
+
buckets = api_session.send(Bkblz::V1::ListBucketsRequest.new).buckets
|
45
|
+
bucket = buckets.select { |b| b.bucket_name == "my-test-bucket" }.first
|
46
|
+
Bkblz.log.info "bucket list => #{buckets}"
|
47
|
+
|
48
|
+
Bkblz.log.info do <<EOS
|
49
|
+
# Step 4, otherwise create a new my-test-bucket
|
50
|
+
EOS
|
51
|
+
end
|
52
|
+
unless bucket
|
53
|
+
bucket = Bkblz::V1::Model::Bucket.new \
|
54
|
+
:bucket_name => "my-test-bucket",
|
55
|
+
:bucket_type => "allPrivate",
|
56
|
+
:account_id => api_session.account_id
|
57
|
+
|
58
|
+
Bkblz.log.info do <<EOS
|
59
|
+
# Step 5, pass a model to the CreateBucketRequest,
|
60
|
+
# models are just named wrappers with dynamic methods
|
61
|
+
# around the JSON responses provided back from the Bkblz
|
62
|
+
# API. See lib/bkblz/v1/models.rb for a list of defined API
|
63
|
+
# objects. See Bkblz::V1::Model::Base for how it work.
|
64
|
+
EOS
|
65
|
+
end
|
66
|
+
request = Bkblz::V1::CreateBucketRequest.new bucket
|
67
|
+
Bkblz.log.info "bucket model => #{bucket}"
|
68
|
+
|
69
|
+
# Bkblz::V1::Response objects are returned from +send+. Some
|
70
|
+
# provide a to_model method if they declare the +response_model+
|
71
|
+
# in the class definition.
|
72
|
+
bucket = api_session.send(request).to_model
|
73
|
+
Bkblz.log.info "created bucket => #{bucket.bucket_name}/#{bucket.bucket_id}"
|
74
|
+
end
|
75
|
+
|
76
|
+
Bkblz.log.info do <<EOS
|
77
|
+
# Step 6, uploading a file begins with getting a dynamic URL from the API.
|
78
|
+
EOS
|
79
|
+
end
|
80
|
+
upload_auth = api_session.send(
|
81
|
+
Bkblz::V1::GetUploadUrlRequest.new bucket.bucket_id).to_model
|
82
|
+
Bkblz.log.info "upload file URL => #{upload_auth.upload_url}"
|
83
|
+
|
84
|
+
|
85
|
+
Bkblz.log.info do <<EOS
|
86
|
+
# Step 7, use the upload_auth model (a
|
87
|
+
# Bkblz::V1::Model::UploadAuth) to upload some files.
|
88
|
+
EOS
|
89
|
+
end
|
90
|
+
5.times do |i|
|
91
|
+
body = "some text #{i}"
|
92
|
+
file_name = "some_text_#{i}.txt"
|
93
|
+
content_type = nil
|
94
|
+
|
95
|
+
upload_file_info = api_session.send(
|
96
|
+
Bkblz::V1::UploadFileRequest.new upload_auth, body, file_name,
|
97
|
+
content_type, Time.now.to_i * 1000).to_model
|
98
|
+
Bkblz.log.info "uploaded file => #{upload_file_info.file_name}"
|
99
|
+
end
|
100
|
+
|
101
|
+
Bkblz.log.info do <<EOS
|
102
|
+
# Step 8, we uploaded 5 files above, here we'll read back out
|
103
|
+
# metadata from the first 2 files in the bucket.
|
104
|
+
EOS
|
105
|
+
end
|
106
|
+
list_files_response = api_session.send(
|
107
|
+
Bkblz::V1::ListFileVersionsRequest.new bucket, 2)
|
108
|
+
bucket_files_info = list_files_response.files
|
109
|
+
Bkblz.log.info "first 2 files => #{bucket_files_info.map(&:file_name).join "\n"}"
|
110
|
+
|
111
|
+
Bkblz.log.info do <<EOS
|
112
|
+
# Step 9, the response object returned object is a
|
113
|
+
# Bkblz::Api::PaginatedResponse. Use its +has_more?+ and
|
114
|
+
# +next_request+ methods to page through more results.
|
115
|
+
EOS
|
116
|
+
end
|
117
|
+
while list_files_response.has_more?
|
118
|
+
list_files_response = api_session.send list_files_response.next_request 100
|
119
|
+
bucket_files_info.concat list_files_response.files
|
120
|
+
Bkblz.log.info "next N files => #{list_files_response.files.map(&:file_name).join "\n"}"
|
121
|
+
end
|
122
|
+
|
123
|
+
Bkblz.log.info do <<EOS
|
124
|
+
# Step 10, delete all the files in the bucket that we added. This is
|
125
|
+
# a service requirement to deleting a bucket.
|
126
|
+
EOS
|
127
|
+
end
|
128
|
+
bucket_files_info.each do |file_info|
|
129
|
+
request = Bkblz::V1::DeleteFileVersionRequest.new file_info
|
130
|
+
delete_file_version_response = api_session.send request
|
131
|
+
Bkblz.log.info "deleted file => #{delete_file_version_response.to_model.file_name}"
|
132
|
+
end
|
133
|
+
|
134
|
+
Bkblz.log.info do <<EOS
|
135
|
+
# Step 11, delete the bucket.
|
136
|
+
EOS
|
137
|
+
end
|
138
|
+
request = Bkblz::V1::DeleteBucketRequest.new bucket
|
139
|
+
delete_bucket_response = api_session.send request
|
140
|
+
Bkblz.log.info "deleted bucket => #{bucket.bucket_name}/#{bucket.bucket_id}"
|
141
|
+
end
|
data/Rakefile
ADDED
data/bkblz.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'bkblz/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "bkblz"
|
8
|
+
spec.version = Bkblz::VERSION
|
9
|
+
spec.authors = ["Erick Johnson"]
|
10
|
+
spec.email = ["erick@vos.io"]
|
11
|
+
|
12
|
+
spec.summary = "Bkblz GEM for the Backblaze B2 API. https://www.backblaze.com/b2/docs/"
|
13
|
+
spec.description = spec.description
|
14
|
+
spec.homepage = "https://github.com/erickj/bkblz"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
25
|
+
end
|
data/lib/all.rb
ADDED
data/lib/bkblz.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require "bkblz/config"
|
2
|
+
require "bkblz/logger"
|
3
|
+
|
4
|
+
module Bkblz
|
5
|
+
|
6
|
+
BaseError = Class.new ::StandardError
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def configure(&block)
|
10
|
+
@config = Bkblz::Config.configure @config, &block
|
11
|
+
config_changed
|
12
|
+
end
|
13
|
+
|
14
|
+
def config
|
15
|
+
unless @config
|
16
|
+
@config = Bkblz::Config.configure
|
17
|
+
config_changed
|
18
|
+
end
|
19
|
+
@config
|
20
|
+
end
|
21
|
+
|
22
|
+
def log
|
23
|
+
@logger ||= config_logger
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def config_changed
|
28
|
+
@logger = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def config_logger
|
32
|
+
@logger = Bkblz::Logger.configure config
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/bkblz/config.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Bkblz
|
2
|
+
|
3
|
+
class Config
|
4
|
+
|
5
|
+
CONFIG_VARS = {
|
6
|
+
:application_key => '',
|
7
|
+
:account_id => '',
|
8
|
+
:debug_http => false,
|
9
|
+
|
10
|
+
:log_device => :stderr, # [:stdout, :stderr, :devnull, path, fd]
|
11
|
+
:log_level => :warn, # [:debug, :info, :warn, :error, :fatal, (-6..-1)]
|
12
|
+
:log_colorize => true
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
attr_reader *CONFIG_VARS.keys, :config_map
|
16
|
+
|
17
|
+
def initialize(**config_map)
|
18
|
+
config_map.each do |k,v|
|
19
|
+
# allows attr_reader methods from CONFIG_VAR to work
|
20
|
+
instance_variable_set :"@#{k}", v
|
21
|
+
end
|
22
|
+
|
23
|
+
@config_map = config_map
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def configure(config=nil, &block)
|
28
|
+
map = config ? config.config_map : CONFIG_VARS.dup
|
29
|
+
yield map if block_given?
|
30
|
+
Config.new map
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module CoreExt
|
3
|
+
refine String do
|
4
|
+
def underscore
|
5
|
+
uncamelify = self.gsub /[a-z\W][A-Z]/ do |m|
|
6
|
+
m.gsub /(^.)/, '\1_'
|
7
|
+
end
|
8
|
+
uncamelify.downcase.gsub(/[^a-z0-9]+/, '_')
|
9
|
+
end
|
10
|
+
|
11
|
+
def demodulize
|
12
|
+
self.split('::').last
|
13
|
+
end
|
14
|
+
|
15
|
+
def camelcase
|
16
|
+
self.gsub /_(.)/ do |match|
|
17
|
+
match[1].upcase
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/bkblz/logger.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Bkblz
|
4
|
+
class Logger
|
5
|
+
COLOR_MAP = {
|
6
|
+
:d => :green,
|
7
|
+
:i => :blue,
|
8
|
+
:w => :yellow,
|
9
|
+
:e => :red,
|
10
|
+
:f => :pink
|
11
|
+
}
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def configure(config)
|
15
|
+
device = configure_device config.log_device
|
16
|
+
|
17
|
+
logger = ::Logger.new device
|
18
|
+
class << logger
|
19
|
+
include LoggerDebugLevels
|
20
|
+
end
|
21
|
+
raise "missing logger debug methods" unless logger.respond_to? :debug1
|
22
|
+
|
23
|
+
logger.level = case config.log_level
|
24
|
+
when Symbol, String
|
25
|
+
::Logger.const_get config.log_level.to_s.upcase
|
26
|
+
when Integer
|
27
|
+
# Negative numbers can be used for detailed debug levels
|
28
|
+
config.log_level
|
29
|
+
end
|
30
|
+
|
31
|
+
colorize = config.log_colorize && device.tty?
|
32
|
+
logger.formatter = default_formatter colorize
|
33
|
+
|
34
|
+
if config.log_colorize && !device.tty?
|
35
|
+
logger.warn "disabled log colorization for non-tty"
|
36
|
+
end
|
37
|
+
|
38
|
+
logger
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def configure_device(device_value)
|
43
|
+
case device_value
|
44
|
+
when :stderr
|
45
|
+
STDERR
|
46
|
+
when :stdout
|
47
|
+
STDOUT
|
48
|
+
when :devnull
|
49
|
+
File.open File::NULL, "w"
|
50
|
+
when Integer
|
51
|
+
IO.new device_value, 'a'
|
52
|
+
when String
|
53
|
+
File.new device_value 'a'
|
54
|
+
else
|
55
|
+
raise ConfigError, "log_device => #{device_value}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def default_formatter(colorize)
|
60
|
+
lambda do |severity, datetime, progname, msg|
|
61
|
+
s_key = severity[0].downcase.to_sym
|
62
|
+
if colorize && COLOR_MAP[s_key]
|
63
|
+
severity = Styleizer.apply severity, COLOR_MAP[s_key]
|
64
|
+
progname = Styleizer.apply progname, :bold, :dark_gray
|
65
|
+
end
|
66
|
+
|
67
|
+
if progname
|
68
|
+
"[%s] (%s): %s\n" % [severity, progname, msg]
|
69
|
+
else
|
70
|
+
"[%s] %s\n" % [severity, msg]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module LoggerDebugLevels
|
77
|
+
NUM_DEBUG_LEVELS = 6
|
78
|
+
|
79
|
+
##
|
80
|
+
# Adds methods debug1, debug2, ... debug6 for more detailed
|
81
|
+
# debug levels. Set a negative index +logger.level+ to enable
|
82
|
+
# lower levels, e.g. logger.level = -6 for debug6 messages.
|
83
|
+
(1..NUM_DEBUG_LEVELS).to_a.each do |debug_level|
|
84
|
+
debug_method_name = "debug#{debug_level}"
|
85
|
+
|
86
|
+
define_method debug_method_name do |*args, &block|
|
87
|
+
severity = debug_level * -1
|
88
|
+
return if severity < self.level
|
89
|
+
|
90
|
+
debug_at_level severity, *args, &block
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def format_severity(severity)
|
95
|
+
if severity < ::Logger::DEBUG
|
96
|
+
return "D" + severity.abs.to_s
|
97
|
+
else
|
98
|
+
super(severity)[0]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
def debug_at_level(severity, progname=nil, &block)
|
104
|
+
raise 'block required for super debug loggers' unless block_given?
|
105
|
+
raise 'progname required for super debug loggers' unless progname
|
106
|
+
|
107
|
+
add severity, nil, progname, &block
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class Styleizer
|
112
|
+
class << self
|
113
|
+
|
114
|
+
STYLE_CODES = {
|
115
|
+
:bold => 1,
|
116
|
+
:red => 31,
|
117
|
+
:green => 32,
|
118
|
+
:yellow => 33,
|
119
|
+
:blue => 34,
|
120
|
+
:pink => 35,
|
121
|
+
:light_blue => 36,
|
122
|
+
:light_gray => 37,
|
123
|
+
:dark_gray => 90
|
124
|
+
}
|
125
|
+
|
126
|
+
def apply(str, *styles)
|
127
|
+
return str unless str
|
128
|
+
styles.reduce(str) { |str, style| styleize STYLE_CODES[style], str }
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
def styleize(color_code, str)
|
133
|
+
"\e[#{color_code}m#{str}\e[0m"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Bkblz
|
2
|
+
class MapKeyFormatter
|
3
|
+
using Bkblz::CoreExt
|
4
|
+
|
5
|
+
def self.underscore_keys(map)
|
6
|
+
modified_map = {}
|
7
|
+
map.each do |k,v|
|
8
|
+
modified_map[k.to_s.underscore.to_sym] = v
|
9
|
+
end
|
10
|
+
modified_map
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.camelcase_keys(map)
|
14
|
+
modified_map = {}
|
15
|
+
map.each do |k,v|
|
16
|
+
modified_map[k.to_s.camelcase.to_sym] = v
|
17
|
+
end
|
18
|
+
modified_map
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/bkblz/v1/all.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative "model_base"
|
2
|
+
require_relative "models"
|
3
|
+
|
4
|
+
require_relative "session"
|
5
|
+
require_relative "response"
|
6
|
+
require_relative "request"
|
7
|
+
require_relative "error_response"
|
8
|
+
|
9
|
+
require_relative "authorize_account"
|
10
|
+
require_relative "list_buckets"
|
11
|
+
require_relative "create_bucket"
|
12
|
+
require_relative "delete_bucket"
|
13
|
+
require_relative "get_upload_url"
|
14
|
+
require_relative "upload_file"
|
15
|
+
require_relative "list_file_versions"
|
16
|
+
require_relative "delete_file_version"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
class AuthorizeAccountResponse < Response
|
4
|
+
response_accessors :account_id,
|
5
|
+
:api_url,
|
6
|
+
:authorization_token,
|
7
|
+
:download_url,
|
8
|
+
:minimum_part_size
|
9
|
+
end
|
10
|
+
|
11
|
+
class AuthorizeAccountRequest < Request
|
12
|
+
|
13
|
+
API_URL = "https://api.backblaze.com/b2api/v1/b2_authorize_account"
|
14
|
+
|
15
|
+
response_class AuthorizeAccountResponse
|
16
|
+
|
17
|
+
def build_request(session)
|
18
|
+
req = Net::HTTP::Get.new URI(API_URL)
|
19
|
+
req.basic_auth(session.config.account_id, session.config.application_key)
|
20
|
+
req
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class CreateBucketResponse < Response
|
5
|
+
response_model Model::Bucket
|
6
|
+
end
|
7
|
+
|
8
|
+
class CreateBucketRequest < Request
|
9
|
+
|
10
|
+
response_class CreateBucketResponse
|
11
|
+
url_suffix "/b2api/v1/b2_create_bucket"
|
12
|
+
|
13
|
+
def initialize(bucket_model)
|
14
|
+
@body = bucket_model.to_map
|
15
|
+
end
|
16
|
+
|
17
|
+
def build_request(session)
|
18
|
+
session.create_post url(session), @body
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class DeleteBucketResponse < Response
|
5
|
+
response_model Model::Bucket
|
6
|
+
end
|
7
|
+
|
8
|
+
class DeleteBucketRequest < Request
|
9
|
+
|
10
|
+
response_class DeleteBucketResponse
|
11
|
+
url_suffix "/b2api/v1/b2_delete_bucket"
|
12
|
+
|
13
|
+
def initialize(bucket_model)
|
14
|
+
@body = {:bucket_id => bucket_model.bucket_id,
|
15
|
+
:account_id => bucket_model.account_id}
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_request(session)
|
19
|
+
session.create_post url(session), @body
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class DeleteFileVersionResponse < Response
|
5
|
+
response_model Model::PartialFileInfo
|
6
|
+
end
|
7
|
+
|
8
|
+
class DeleteFileVersionRequest < Request
|
9
|
+
|
10
|
+
response_class DeleteFileVersionResponse
|
11
|
+
url_suffix "/b2api/v1/b2_delete_file_version"
|
12
|
+
|
13
|
+
def initialize(short_file_info)
|
14
|
+
@body = {:file_name => short_file_info.file_name,
|
15
|
+
:file_id => short_file_info.file_id}
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_request(session)
|
19
|
+
session.create_post url(session), @body
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
class ErrorResponse < Response
|
4
|
+
|
5
|
+
response_model V1::Model::Error
|
6
|
+
|
7
|
+
ERROR_TYPE = {
|
8
|
+
400 => :BAD_REQUEST,
|
9
|
+
401 => :UNAUTHORIZED,
|
10
|
+
403 => :FORBIDDEN,
|
11
|
+
408 => :REQUEST_TIMEOUT,
|
12
|
+
429 => :TOO_MANY_REQUESTS,
|
13
|
+
500 => :INTERNAL_ERROR,
|
14
|
+
503 => :SERVICE_UNAVAILABLE
|
15
|
+
}
|
16
|
+
|
17
|
+
def message
|
18
|
+
model = self.to_model
|
19
|
+
error_type = ERROR_TYPE[model.status]
|
20
|
+
"[#{model.status}:#{error_type}:#{model.code}] #{model.message}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class GetUploadUrlResponse < Response
|
5
|
+
response_model Model::UploadAuth
|
6
|
+
end
|
7
|
+
|
8
|
+
class GetUploadUrlRequest < Request
|
9
|
+
|
10
|
+
response_class GetUploadUrlResponse
|
11
|
+
url_suffix "/b2api/v1/b2_get_upload_url"
|
12
|
+
|
13
|
+
def initialize(bucket_id)
|
14
|
+
@body = {:bucket_id => bucket_id}
|
15
|
+
end
|
16
|
+
|
17
|
+
def build_request(session)
|
18
|
+
session.create_post url(session), @body
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class ListBucketsResponse < Response
|
5
|
+
response_accessor :buckets, Model::Bucket
|
6
|
+
end
|
7
|
+
|
8
|
+
class ListBucketsRequest < Request
|
9
|
+
|
10
|
+
response_class ListBucketsResponse
|
11
|
+
url_suffix "/b2api/v1/b2_list_buckets"
|
12
|
+
|
13
|
+
def build_request(session)
|
14
|
+
session.create_post url(session), :account_id => session.account_id
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class ListFileVersionsResponse < PaginatedResponse
|
5
|
+
response_accessor :files, Model::FileInfo
|
6
|
+
pagination_accessors :next_file_name, :next_file_id
|
7
|
+
|
8
|
+
def build_next_request(limit)
|
9
|
+
bucket = original_request.bucket
|
10
|
+
ListFileVersionsRequest.new bucket, limit, self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ListFileVersionsRequest < Request
|
15
|
+
|
16
|
+
response_class ListFileVersionsResponse
|
17
|
+
url_suffix "/b2api/v1/b2_list_file_versions"
|
18
|
+
|
19
|
+
attr_reader :bucket
|
20
|
+
|
21
|
+
def initialize(bucket, max_file_count=1000, paginate_from=nil)
|
22
|
+
@bucket = bucket
|
23
|
+
@body = {}
|
24
|
+
@body[:bucket_id] = bucket.bucket_id
|
25
|
+
@body[:max_file_count] = max_file_count
|
26
|
+
|
27
|
+
if paginate_from
|
28
|
+
raise 'invalid paginator' unless paginate_from.is_a? ListFileVersionsResponse
|
29
|
+
|
30
|
+
next_file_name = paginate_from.next_file_name
|
31
|
+
next_file_id = paginate_from.next_file_id
|
32
|
+
|
33
|
+
@body[:start_file_name] = next_file_name if next_file_name
|
34
|
+
@body[:start_file_id] = next_file_id if next_file_id
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_request(session)
|
39
|
+
session.create_post url(session), @body
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
module Model
|
4
|
+
|
5
|
+
def self.define(*fields)
|
6
|
+
model_klass = Class.new BaseModel
|
7
|
+
model_klass.field_accessors *fields
|
8
|
+
model_klass
|
9
|
+
end
|
10
|
+
|
11
|
+
class BaseModel
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def field_accessors(*fields)
|
15
|
+
fields.each do |field|
|
16
|
+
define_method field do |*args|
|
17
|
+
@map[field]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(map)
|
24
|
+
@map = map
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_map
|
28
|
+
@map.dup
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
"#<%s:%d %s>" % [self.class.name, __id__, @map]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
module Model
|
4
|
+
|
5
|
+
# Returned by list_buckets, create_bucket, delete_bucket
|
6
|
+
Bucket = Model.define :account_id, :bucket_id, :bucket_name, :bucket_type
|
7
|
+
|
8
|
+
# Returned by list_file_versions
|
9
|
+
File = Model.define *[
|
10
|
+
:action, :content_length, :file_id, :file_name, :size, :upload_timestamp
|
11
|
+
]
|
12
|
+
|
13
|
+
# Returned by upload_file
|
14
|
+
FileInfo = Model.define *[
|
15
|
+
:account_id, :bucket_id, :content_length, :content_sha1, :content_type,
|
16
|
+
:file_id, :file_info, :file_name
|
17
|
+
]
|
18
|
+
|
19
|
+
# Returned by delete_file_version
|
20
|
+
PartialFileInfo = Model.define :file_id, :file_name
|
21
|
+
|
22
|
+
# Returned by get_upload_url
|
23
|
+
UploadAuth = Model.define :bucket_id, :upload_url, :authorization_token
|
24
|
+
|
25
|
+
# Possibly returned by any request
|
26
|
+
Error = Model.define :status, :code, :message
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Bkblz
|
4
|
+
module V1
|
5
|
+
|
6
|
+
TooManyRedirectError = Class.new Bkblz::BaseError
|
7
|
+
|
8
|
+
class RequestError < Bkblz::BaseError
|
9
|
+
def initialize(error_response)
|
10
|
+
super error_response.message
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Request
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def response_class(klass=nil)
|
18
|
+
@response_class = klass unless klass.nil?
|
19
|
+
@response_class
|
20
|
+
end
|
21
|
+
|
22
|
+
def url_suffix(suffix=nil)
|
23
|
+
@url_suffix = suffix unless suffix.nil?
|
24
|
+
@url_suffix
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def send(session)
|
29
|
+
request = build_request session
|
30
|
+
Bkblz.log.debug { "sending request => #{request} to URI => #{request.uri}" }
|
31
|
+
http = Net::HTTP.new(request.uri.host, request.uri.port)
|
32
|
+
http.use_ssl = true
|
33
|
+
http.set_debug_output(STDERR) if session.config.debug_http
|
34
|
+
|
35
|
+
build_response fetch(http, request)
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def build_request(session)
|
41
|
+
raise 'not implemented'
|
42
|
+
end
|
43
|
+
|
44
|
+
def build_response(response)
|
45
|
+
unless response.kind_of? Net::HTTPSuccess
|
46
|
+
error_response = ErrorResponse.new response, self
|
47
|
+
raise RequestError.new error_response
|
48
|
+
end
|
49
|
+
Bkblz.log.debug { "#build_response => #{response}" }
|
50
|
+
|
51
|
+
response_class = self.class.response_class || Response
|
52
|
+
response_class.new response, self
|
53
|
+
end
|
54
|
+
|
55
|
+
def url(session)
|
56
|
+
raise "no URL suffix for #{self.class}" unless self.class.url_suffix
|
57
|
+
session.create_url(self.class.url_suffix)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def fetch(http, request, limit=10)
|
63
|
+
# You should choose a better exception.
|
64
|
+
raise TooManyRedirectError, 'too many HTTP redirects' if limit == 0
|
65
|
+
|
66
|
+
response = http.start { |http| http.request(request) }
|
67
|
+
|
68
|
+
case response
|
69
|
+
when Net::HTTPSuccess then
|
70
|
+
response
|
71
|
+
when Net::HTTPRedirection then
|
72
|
+
location = response['location']
|
73
|
+
Bkblz.log.warn "redirected to #{location}"
|
74
|
+
fetch http, location, limit - 1
|
75
|
+
else
|
76
|
+
response
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Bkblz
|
4
|
+
module V1
|
5
|
+
class Response
|
6
|
+
|
7
|
+
MissingResponseError = Class.new Bkblz::BaseError
|
8
|
+
|
9
|
+
attr_reader :parsed_body, :http_response
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
def response_model(klass=nil)
|
14
|
+
@response_model = klass unless klass.nil?
|
15
|
+
@response_model
|
16
|
+
end
|
17
|
+
|
18
|
+
def response_accessors(*response_fields)
|
19
|
+
response_fields.each do |response_field|
|
20
|
+
response_accessor response_field
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def response_accessor(response_field, model_klass=nil, &block)
|
25
|
+
api_map_key_converter = lambda do |map|
|
26
|
+
raise "not a Hash" unless map.is_a? Hash
|
27
|
+
Bkblz::MapKeyFormatter.underscore_keys map
|
28
|
+
end
|
29
|
+
api_value_transformer = lambda do |value|
|
30
|
+
return value unless model_klass || block_given?
|
31
|
+
return yield value if block_given?
|
32
|
+
|
33
|
+
if value.is_a? Array
|
34
|
+
value.map do |v|
|
35
|
+
model_klass.new api_map_key_converter.call(v)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
model_klass.new api_map_key_converter.call(value)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
define_method response_field do |*args|
|
43
|
+
raise MissingResponseError unless @parsed_response
|
44
|
+
return @cache[response_field] if @cache.key? response_field
|
45
|
+
|
46
|
+
value = @parsed_response[response_field]
|
47
|
+
@cache[response_field] = api_value_transformer.call value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize(http_response, original_request)
|
53
|
+
@http_response = http_response
|
54
|
+
@original_request = original_request
|
55
|
+
|
56
|
+
@parsed_response = parse http_response
|
57
|
+
@cache = {}
|
58
|
+
Bkblz.log.debug { "parsed response => #{@parsed_response}" }
|
59
|
+
end
|
60
|
+
|
61
|
+
attr_reader :original_request
|
62
|
+
protected :original_request
|
63
|
+
|
64
|
+
def [](key)
|
65
|
+
@parsed_response[key]
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_model
|
69
|
+
raise 'no response model defined' unless self.class.response_model
|
70
|
+
self.class.response_model.new @parsed_response.dup
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def parse(http_response)
|
75
|
+
parsed_json = JSON.parse http_response.body, {
|
76
|
+
:allow_nan => true,
|
77
|
+
:symbolize_names => true,
|
78
|
+
:max_nesting => 4
|
79
|
+
}
|
80
|
+
Bkblz::MapKeyFormatter.underscore_keys parsed_json
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class PaginatedResponse < Response
|
85
|
+
|
86
|
+
NoMorePagesError = Class.new Bkblz::BaseError
|
87
|
+
|
88
|
+
class << self
|
89
|
+
|
90
|
+
attr_reader :pagination_fields
|
91
|
+
def pagination_accessors(*pagination_fields)
|
92
|
+
response_accessors *pagination_fields
|
93
|
+
|
94
|
+
@pagination_fields ||= []
|
95
|
+
@pagination_fields.concat pagination_fields
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def has_more?
|
100
|
+
self.class.pagination_fields.any? { |f| !self[f].nil? }
|
101
|
+
end
|
102
|
+
|
103
|
+
def next_request(limit=nil)
|
104
|
+
raise NoMorePagesError unless has_more?
|
105
|
+
build_next_request(limit)
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
def build_next_request(limit)
|
110
|
+
raise "not implemented"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Bkblz
|
4
|
+
module V1
|
5
|
+
|
6
|
+
SessionNotAuthorizedError = Class.new Bkblz::BaseError
|
7
|
+
|
8
|
+
class Session
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def authorize(config, &block)
|
12
|
+
session = Session.new config
|
13
|
+
session.auth_response =
|
14
|
+
session.send Bkblz::V1::AuthorizeAccountRequest.new
|
15
|
+
|
16
|
+
yield(session) if block_given?
|
17
|
+
session
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_accessor :config, :auth_response
|
22
|
+
|
23
|
+
def initialize(config)
|
24
|
+
@config = config
|
25
|
+
end
|
26
|
+
|
27
|
+
def send(request)
|
28
|
+
request.send self
|
29
|
+
end
|
30
|
+
|
31
|
+
def account_id
|
32
|
+
check_authorized
|
33
|
+
auth_response.account_id
|
34
|
+
end
|
35
|
+
|
36
|
+
def authorized?
|
37
|
+
!!auth_response && !!auth_response.authorization_token
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_url(url_suffix)
|
41
|
+
check_authorized
|
42
|
+
URI.join auth_response.api_url, url_suffix
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_post(url, body=nil, addl_headers={})
|
46
|
+
Bkblz.log.debug { "creating post for request => #{url}" }
|
47
|
+
check_authorized
|
48
|
+
|
49
|
+
uri = url.is_a?(URI) ? url : URI(url)
|
50
|
+
request = Net::HTTP::Post.new uri
|
51
|
+
|
52
|
+
if body.is_a? Hash
|
53
|
+
body = Bkblz::MapKeyFormatter.camelcase_keys(body).to_json
|
54
|
+
end
|
55
|
+
request.body = body if body
|
56
|
+
|
57
|
+
headers = {:"Authorization" => auth_response.authorization_token}
|
58
|
+
headers.merge(addl_headers).each do |k,v|
|
59
|
+
Bkblz.log.debug2 { "adding request header => #{k}:#{v}" }
|
60
|
+
request.add_field k.to_s, v unless v.nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
request
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def check_authorized
|
68
|
+
raise SessionNotAuthorizedError unless authorized?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "digest/sha1"
|
2
|
+
|
3
|
+
module Bkblz
|
4
|
+
module V1
|
5
|
+
|
6
|
+
TooManyBzInfoHeadersError = Class.new Bkblz::BaseError
|
7
|
+
|
8
|
+
class UploadFileResponse < Response
|
9
|
+
response_model Model::FileInfo
|
10
|
+
end
|
11
|
+
|
12
|
+
class UploadFileRequest < Request
|
13
|
+
|
14
|
+
response_class UploadFileResponse
|
15
|
+
|
16
|
+
REQUIRED_HEADERS = {
|
17
|
+
:"Authorization" => nil,
|
18
|
+
:"X-Bz-File-Name" => nil,
|
19
|
+
:"Content-Type" => "b2/x-auto",
|
20
|
+
:"Content-Length" => nil,
|
21
|
+
:"X-Bz-Content-Sha1" => nil
|
22
|
+
}
|
23
|
+
|
24
|
+
def initialize(upload_auth, body, file_name, content_type=nil,
|
25
|
+
last_modified_millis=nil, **bz_info)
|
26
|
+
unless last_modified_millis
|
27
|
+
# Recommended https://www.backblaze.com/b2/docs/b2_upload_file.html
|
28
|
+
bz_info["src_last_modified_millis"] = last_modified_millis
|
29
|
+
end
|
30
|
+
raise TooManyBzInfoHeadersError, bz_info_headers if bz_info.size > 10
|
31
|
+
|
32
|
+
@upload_url = upload_auth.upload_url
|
33
|
+
@body = body.is_a?(IO) ? body.read : body
|
34
|
+
@headers = REQUIRED_HEADERS.dup
|
35
|
+
bz_info.each do |k,v|
|
36
|
+
@headers["X-Bz-Info-#{k.to-s}".to_sym] = v
|
37
|
+
end
|
38
|
+
|
39
|
+
@headers[:"Authorization"] = upload_auth.authorization_token
|
40
|
+
@headers[:"X-Bz-File-Name"] = file_name
|
41
|
+
@headers[:"Content-Length"] = @body.size
|
42
|
+
@headers[:"X-Bz-Content-Sha1"] = Digest::SHA1.hexdigest @body
|
43
|
+
end
|
44
|
+
|
45
|
+
def build_request(session)
|
46
|
+
session.create_post @upload_url, @body, @headers
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bkblz
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Erick Johnson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-11-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: ''
|
56
|
+
email:
|
57
|
+
- erick@vos.io
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".travis.yml"
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.rb
|
68
|
+
- Rakefile
|
69
|
+
- bkblz.gemspec
|
70
|
+
- lib/all.rb
|
71
|
+
- lib/bkblz.rb
|
72
|
+
- lib/bkblz/config.rb
|
73
|
+
- lib/bkblz/core_ext.rb
|
74
|
+
- lib/bkblz/logger.rb
|
75
|
+
- lib/bkblz/map_key_formatter.rb
|
76
|
+
- lib/bkblz/v1/all.rb
|
77
|
+
- lib/bkblz/v1/authorize_account.rb
|
78
|
+
- lib/bkblz/v1/create_bucket.rb
|
79
|
+
- lib/bkblz/v1/delete_bucket.rb
|
80
|
+
- lib/bkblz/v1/delete_file_version.rb
|
81
|
+
- lib/bkblz/v1/error_response.rb
|
82
|
+
- lib/bkblz/v1/get_upload_url.rb
|
83
|
+
- lib/bkblz/v1/list_buckets.rb
|
84
|
+
- lib/bkblz/v1/list_file_versions.rb
|
85
|
+
- lib/bkblz/v1/model_base.rb
|
86
|
+
- lib/bkblz/v1/models.rb
|
87
|
+
- lib/bkblz/v1/request.rb
|
88
|
+
- lib/bkblz/v1/response.rb
|
89
|
+
- lib/bkblz/v1/session.rb
|
90
|
+
- lib/bkblz/v1/upload_file.rb
|
91
|
+
- lib/bkblz/version.rb
|
92
|
+
homepage: https://github.com/erickj/bkblz
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.5.1
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: Bkblz GEM for the Backblaze B2 API. https://www.backblaze.com/b2/docs/
|
116
|
+
test_files: []
|