tumugi-plugin-google_cloud_storage 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 +10 -0
- data/.travis.yml +13 -0
- data/Gemfile +4 -0
- data/README.md +87 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/example.rb +11 -0
- data/examples/tumugi_config_example.rb +7 -0
- data/lib/tumugi/plugin/google_cloud_storage/atomic_file.rb +18 -0
- data/lib/tumugi/plugin/google_cloud_storage/file_system.rb +299 -0
- data/lib/tumugi/plugin/target/google_cloud_storage_file.rb +41 -0
- data/tumugi-plugin-google_cloud_storage.gemspec +31 -0
- metadata +169 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a54e93d2ae132b0372b36c6f3d1974c1fbb7ef92
|
4
|
+
data.tar.gz: 6c1c6aa1fe96b655ab3f8f9b49176ef34dc9858f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 83efe8fafc377ac90a8fc103bcee1195fb80296330a50b8a28d6c029037e19b1b29f0e15337a8443313f6fa643311ccc42a9b9747bf4308bc183bb454bacd4ed
|
7
|
+
data.tar.gz: f2ce008443eaf65118d94650698ec6ccf4b2ebf07d6079ae11a2ac7d28da8992cb683dae22cb20f6558dcc7603a41e0d2b1843a804f7bb2545e8e164aac13a71
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
[](https://travis-ci.org/tumugi/tumugi-plugin-google_cloud_storage) [](https://codeclimate.com/github/tumugi/tumugi-plugin-google_cloud_storage) [](https://coveralls.io/github/tumugi/tumugi-plugin-google_cloud_storage?branch=master) [](https://badge.fury.io/rb/tumugi-plugin-google_cloud_storage)
|
2
|
+
|
3
|
+
# tumugi-plugin-google_cloud_storage
|
4
|
+
|
5
|
+
[tumugi](https://github.com/tumugi/tumugi) plugin for Google Cloud Storage.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'tumugi-plugin-google_cloud_storage'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
```sh
|
18
|
+
$ bundle
|
19
|
+
```
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
```sh
|
24
|
+
$ gem install tumugi-plugin-google_cloud_storage
|
25
|
+
```
|
26
|
+
|
27
|
+
## Component
|
28
|
+
|
29
|
+
### Tumugi::Plugin::GoogleCloudStorageFileTarget
|
30
|
+
|
31
|
+
This target represent file or directory on Googl Cloud Storage.
|
32
|
+
This target has 2 parameters, `bucket` and `key`.
|
33
|
+
|
34
|
+
Tumugi workflow file using this target is like this:
|
35
|
+
|
36
|
+
```rb
|
37
|
+
task :task1 do
|
38
|
+
param :bucket, type: :string, auto_bind: true, required: true
|
39
|
+
param :day, type: :time, auto_bind: true, required: true
|
40
|
+
output do
|
41
|
+
target(:google_cloud_storage_file, bucket: bucket, key: "test_#{day.strftime('%Y%m%d')}.txt")
|
42
|
+
end
|
43
|
+
run do
|
44
|
+
log 'task1#run'
|
45
|
+
output.open('w') {|f| f.puts('done') }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
### Config Section
|
51
|
+
|
52
|
+
tumugi-plugin-google_cloud_storage provide config section named "google_cloud_storage" which can specified Google Cloud Storage autenticaion info.
|
53
|
+
|
54
|
+
#### Authenticate by client_email and private_key
|
55
|
+
|
56
|
+
```rb
|
57
|
+
Tumugi.config do |config|
|
58
|
+
config.section("google_cloud_storage") do |section|
|
59
|
+
section.project_id = "xxx"
|
60
|
+
section.client_email = "yyy@yyy.iam.gserviceaccount.com"
|
61
|
+
section.private_key = "zzz"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
#### Authenticate by JSON key file
|
67
|
+
|
68
|
+
```rb
|
69
|
+
Tumugi.configure do |config|
|
70
|
+
config.section("google_cloud_storage") do |section|
|
71
|
+
section.private_key_file = "/path/to/key.json"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
## Development
|
77
|
+
|
78
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
79
|
+
|
80
|
+
## Contributing
|
81
|
+
|
82
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/tumugi/ttumugi-plugin-google_cloud_storage
|
83
|
+
|
84
|
+
## License
|
85
|
+
|
86
|
+
The gem is available as open source under the terms of the [Apache License
|
87
|
+
Version 2.0](http://www.apache.org/licenses/).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "tumugi/plugin/gcs"
|
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 "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/examples/example.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
task :task1 do
|
2
|
+
param :bucket, type: :string, auto_bind: true, required: true
|
3
|
+
param :day, type: :time, auto_bind: true, required: true
|
4
|
+
output do
|
5
|
+
target(:google_cloud_storage_file, bucket: bucket, key: "test_#{day.strftime('%Y%m%d')}.txt")
|
6
|
+
end
|
7
|
+
run do
|
8
|
+
log 'task1#run'
|
9
|
+
output.open('w') {|f| f.puts('done') }
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'tumugi/atomic_file'
|
2
|
+
|
3
|
+
module Tumugi
|
4
|
+
module Plugin
|
5
|
+
module GoogleCloudStorage
|
6
|
+
class AtomicFile < Tumugi::AtomicFile
|
7
|
+
def initialize(path, client)
|
8
|
+
super(path)
|
9
|
+
@client = client
|
10
|
+
end
|
11
|
+
|
12
|
+
def move_to_final_destination(temp_file)
|
13
|
+
@client.upload(temp_file, path)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,299 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'json'
|
3
|
+
require 'google/apis/storage_v1'
|
4
|
+
require 'tumugi/file_system'
|
5
|
+
|
6
|
+
module Tumugi
|
7
|
+
module Plugin
|
8
|
+
module GoogleCloudStorage
|
9
|
+
class FileSystem < Tumugi::FileSystem
|
10
|
+
attr_reader :client
|
11
|
+
|
12
|
+
def initialize(config)
|
13
|
+
@client = create_client(config)
|
14
|
+
end
|
15
|
+
|
16
|
+
#######################################################################
|
17
|
+
# FileSystem interfaces
|
18
|
+
#######################################################################
|
19
|
+
|
20
|
+
def exist?(path)
|
21
|
+
bucket, key = path_to_bucket_and_key(path)
|
22
|
+
if obj_exist?(bucket, key)
|
23
|
+
true
|
24
|
+
else
|
25
|
+
directory?(path)
|
26
|
+
end
|
27
|
+
rescue
|
28
|
+
process_error($!)
|
29
|
+
end
|
30
|
+
|
31
|
+
def remove(path, recursive: true)
|
32
|
+
bucket, key = path_to_bucket_and_key(path)
|
33
|
+
raise Tumugi::FileSystemError.new("Cannot delete root of bucket at path '#{path}'") if root?(key)
|
34
|
+
|
35
|
+
if obj_exist?(bucket, key)
|
36
|
+
@client.delete_object(bucket, key)
|
37
|
+
wait_until { !obj_exist?(bucket, key) }
|
38
|
+
true
|
39
|
+
elsif directory?(path)
|
40
|
+
raise Tumugi::FileSystemError.new("Path '#{path}' is a directory. Must use recursive delete") if !recursive
|
41
|
+
|
42
|
+
objs = entries(path).map(&:name)
|
43
|
+
@client.batch do |client|
|
44
|
+
objs.each do |obj|
|
45
|
+
client.delete_object(bucket, obj)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
wait_until { !directory?(path) }
|
49
|
+
true
|
50
|
+
else
|
51
|
+
false
|
52
|
+
end
|
53
|
+
rescue
|
54
|
+
process_error($!)
|
55
|
+
end
|
56
|
+
|
57
|
+
def mkdir(path, parents: true, raise_if_exist: false)
|
58
|
+
if exist?(path)
|
59
|
+
if raise_if_exist
|
60
|
+
raise Tumugi::FileAlreadyExistError.new("Path #{path} is already exist")
|
61
|
+
elsif !directory?(path)
|
62
|
+
raise Tumugi::NotADirectoryError.new("Path #{path} is not a directory")
|
63
|
+
end
|
64
|
+
false
|
65
|
+
else
|
66
|
+
put_string("", add_path_delimiter(path))
|
67
|
+
true
|
68
|
+
end
|
69
|
+
rescue
|
70
|
+
process_error($!)
|
71
|
+
end
|
72
|
+
|
73
|
+
def directory?(path)
|
74
|
+
bucket, key = path_to_bucket_and_key(path)
|
75
|
+
if root?(key)
|
76
|
+
bucket_exist?(bucket)
|
77
|
+
else
|
78
|
+
obj = add_path_delimiter(key)
|
79
|
+
if obj_exist?(bucket, obj)
|
80
|
+
true
|
81
|
+
else
|
82
|
+
# Any objects with this prefix
|
83
|
+
objects = @client.list_objects(bucket, prefix: obj, max_results: 20)
|
84
|
+
!!(objects.items && objects.items.size > 0)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
rescue
|
88
|
+
process_error($!)
|
89
|
+
end
|
90
|
+
|
91
|
+
def entries(path)
|
92
|
+
bucket, key = path_to_bucket_and_key(path)
|
93
|
+
obj = add_path_delimiter(key)
|
94
|
+
results = []
|
95
|
+
next_page_token = ''
|
96
|
+
|
97
|
+
until next_page_token.nil?
|
98
|
+
objects = @client.list_objects(bucket, prefix: obj, page_token: next_page_token)
|
99
|
+
if objects && objects.items
|
100
|
+
results.concat(objects.items)
|
101
|
+
next_page_token = objects.next_page_token
|
102
|
+
else
|
103
|
+
next_page_token = nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
results
|
107
|
+
rescue
|
108
|
+
process_error($!)
|
109
|
+
end
|
110
|
+
|
111
|
+
def move(src_path, dest_path, raise_if_exist: false)
|
112
|
+
copy(src_path, dest_path, raise_if_exist: raise_if_exist)
|
113
|
+
remove(src_path)
|
114
|
+
end
|
115
|
+
|
116
|
+
#######################################################################
|
117
|
+
# Specific methods
|
118
|
+
#######################################################################
|
119
|
+
|
120
|
+
def upload(media, path, content_type: nil)
|
121
|
+
bucket, key = path_to_bucket_and_key(path)
|
122
|
+
obj = Google::Apis::StorageV1::Object.new(bucket: bucket, name: key)
|
123
|
+
@client.insert_object(bucket, obj, upload_source: media, content_type: content_type)
|
124
|
+
wait_until { obj_exist?(bucket, key) }
|
125
|
+
rescue
|
126
|
+
process_error($!)
|
127
|
+
end
|
128
|
+
|
129
|
+
def download(path, download_path: nil, mode: 'r', &block)
|
130
|
+
bucket, key = path_to_bucket_and_key(path)
|
131
|
+
if download_path.nil?
|
132
|
+
download_path = Tempfile.new('tumugi_gcs_file_system').path
|
133
|
+
end
|
134
|
+
@client.get_object(bucket, key, download_dest: download_path)
|
135
|
+
wait_until { File.exist?(download_path) }
|
136
|
+
|
137
|
+
if block_given?
|
138
|
+
File.open(download_path, mode, &block)
|
139
|
+
else
|
140
|
+
File.open(download_path, mode)
|
141
|
+
end
|
142
|
+
rescue
|
143
|
+
process_error($!)
|
144
|
+
end
|
145
|
+
|
146
|
+
def put_string(contents, path, content_type: 'text/plain')
|
147
|
+
media = StringIO.new(contents)
|
148
|
+
upload(media, path, content_type: content_type)
|
149
|
+
end
|
150
|
+
|
151
|
+
def copy(src_path, dest_path, raise_if_exist: false)
|
152
|
+
if raise_if_exist && exist?(dest_path)
|
153
|
+
raise Tumugi::FileAlreadyExistError.new("Path #{dest_path} is already exist")
|
154
|
+
end
|
155
|
+
|
156
|
+
src_bucket, src_key = path_to_bucket_and_key(src_path)
|
157
|
+
dest_bucket, dest_key = path_to_bucket_and_key(dest_path)
|
158
|
+
|
159
|
+
if directory?(src_path)
|
160
|
+
src_prefix = add_path_delimiter(src_key)
|
161
|
+
dest_prefix = add_path_delimiter(dest_key)
|
162
|
+
|
163
|
+
src_path = add_path_delimiter(src_path)
|
164
|
+
copied_objs = []
|
165
|
+
entries(src_path).each do |entry|
|
166
|
+
suffix = entry.name[src_prefix.length..-1]
|
167
|
+
@client.copy_object(src_bucket, src_prefix + suffix,
|
168
|
+
dest_bucket, dest_prefix + suffix)
|
169
|
+
copied_objs << (dest_prefix + suffix)
|
170
|
+
end
|
171
|
+
wait_until { copied_objs.all? {|obj| obj_exist?(dest_bucket, obj)} }
|
172
|
+
else
|
173
|
+
@client.copy_object(src_bucket, src_key, dest_bucket, dest_key)
|
174
|
+
wait_until { obj_exist?(dest_bucket, dest_key) }
|
175
|
+
end
|
176
|
+
rescue
|
177
|
+
process_error($!)
|
178
|
+
end
|
179
|
+
|
180
|
+
def path_to_bucket_and_key(path)
|
181
|
+
uri = URI.parse(path)
|
182
|
+
raise Tumugi::FileSystemError.new("URI scheme must be 'gs' but '#{uri.scheme}'") unless uri.scheme == 'gs'
|
183
|
+
[ uri.host, uri.path[1..-1] ]
|
184
|
+
end
|
185
|
+
|
186
|
+
def create_bucket(bucket)
|
187
|
+
unless bucket_exist?(bucket)
|
188
|
+
b = Google::Apis::StorageV1::Bucket.new(name: bucket)
|
189
|
+
@client.insert_bucket(@project_id, b)
|
190
|
+
true
|
191
|
+
else
|
192
|
+
false
|
193
|
+
end
|
194
|
+
rescue
|
195
|
+
process_error($!)
|
196
|
+
end
|
197
|
+
|
198
|
+
def remove_bucket(bucket)
|
199
|
+
if bucket_exist?(bucket)
|
200
|
+
@client.delete_bucket(bucket)
|
201
|
+
true
|
202
|
+
else
|
203
|
+
false
|
204
|
+
end
|
205
|
+
rescue
|
206
|
+
process_error($!)
|
207
|
+
end
|
208
|
+
|
209
|
+
def bucket_exist?(bucket)
|
210
|
+
@client.get_bucket(bucket)
|
211
|
+
true
|
212
|
+
rescue => e
|
213
|
+
return false if e.status_code == 404
|
214
|
+
process_error(e)
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
def obj_exist?(bucket, key)
|
220
|
+
@client.get_object(bucket, key)
|
221
|
+
true
|
222
|
+
rescue => e
|
223
|
+
return false if e.status_code == 404
|
224
|
+
process_error(e)
|
225
|
+
end
|
226
|
+
|
227
|
+
def root?(key)
|
228
|
+
key.nil? || key == ''
|
229
|
+
end
|
230
|
+
|
231
|
+
def add_path_delimiter(key)
|
232
|
+
if key.end_with?('/')
|
233
|
+
key
|
234
|
+
else
|
235
|
+
"#{key}/"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def create_client(config)
|
240
|
+
if config.private_key_file.nil?
|
241
|
+
@project_id = config.project_id
|
242
|
+
client_email = config.client_email
|
243
|
+
private_key = config.private_key
|
244
|
+
else
|
245
|
+
json = JSON.parse(File.read(config.private_key_file))
|
246
|
+
@project_id = json['project_id']
|
247
|
+
client_email = json['client_email']
|
248
|
+
private_key = json['private_key']
|
249
|
+
end
|
250
|
+
|
251
|
+
# https://cloud.google.com/storage/docs/authentication
|
252
|
+
scope = "https://www.googleapis.com/auth/devstorage.read_write"
|
253
|
+
|
254
|
+
if client_email and private_key
|
255
|
+
auth = Signet::OAuth2::Client.new(
|
256
|
+
token_credential_uri: "https://accounts.google.com/o/oauth2/token",
|
257
|
+
audience: "https://accounts.google.com/o/oauth2/token",
|
258
|
+
scope: scope,
|
259
|
+
issuer: client_email,
|
260
|
+
signing_key: OpenSSL::PKey.read(private_key))
|
261
|
+
# MEMO: signet-0.6.1 depend on Farady.default_connection
|
262
|
+
Faraday.default_connection.options.timeout = 60
|
263
|
+
auth.fetch_access_token!
|
264
|
+
else
|
265
|
+
auth = Google::Auth.get_application_default([scope])
|
266
|
+
auth.fetch_access_token!
|
267
|
+
end
|
268
|
+
|
269
|
+
client = Google::Apis::StorageV1::StorageService.new
|
270
|
+
client.authorization = auth
|
271
|
+
client
|
272
|
+
end
|
273
|
+
|
274
|
+
def wait_until(&block)
|
275
|
+
while not block.call
|
276
|
+
sleep 1
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def process_error(err)
|
281
|
+
if err.respond_to?(:body)
|
282
|
+
begin
|
283
|
+
jobj = JSON.parse(err.body)
|
284
|
+
error = jobj["error"]
|
285
|
+
reason = error["errors"].map{|e| e["reason"]}.join(",")
|
286
|
+
errors = error["errors"].map{|e| e["message"] }.join("\n")
|
287
|
+
rescue JSON::ParserError
|
288
|
+
reason = err.status_code.to_s
|
289
|
+
errors = "HTTP Status: #{err.status_code}\nHeaders: #{err.header.inspect}\nBody:\n#{err.body}"
|
290
|
+
end
|
291
|
+
raise Tumugi::FileSystemError.new(errors, reason)
|
292
|
+
else
|
293
|
+
raise err
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'tumugi/config'
|
2
|
+
require 'tumugi/plugin'
|
3
|
+
require 'tumugi/plugin/file_system_target'
|
4
|
+
require 'tumugi/plugin/google_cloud_storage/atomic_file'
|
5
|
+
require 'tumugi/plugin/google_cloud_storage/file_system'
|
6
|
+
|
7
|
+
module Tumugi
|
8
|
+
module Plugin
|
9
|
+
class GoogleCloudStorageFileTarget < Tumugi::Plugin::FileSystemTarget
|
10
|
+
Tumugi::Plugin.register_target('google_cloud_storage_file', self)
|
11
|
+
Tumugi::Config.register_section('google_cloud_storage', :project_id, :client_email, :private_key, :private_key_file)
|
12
|
+
|
13
|
+
attr_reader :bucket, :key, :path
|
14
|
+
|
15
|
+
def initialize(bucket:, key:)
|
16
|
+
@bucket = bucket
|
17
|
+
@key = key
|
18
|
+
@path = "gs://#{File.join(bucket, key)}"
|
19
|
+
log "bucket='#{bucket}, key='#{key}'"
|
20
|
+
end
|
21
|
+
|
22
|
+
def fs
|
23
|
+
@fs ||= Tumugi::Plugin::GoogleCloudStorage::FileSystem.new(Tumugi.config.section('google_cloud_storage'))
|
24
|
+
end
|
25
|
+
|
26
|
+
def open(mode="r", &block)
|
27
|
+
if mode.include? 'r'
|
28
|
+
fs.download(path, mode: mode, &block)
|
29
|
+
elsif mode.include? 'w'
|
30
|
+
Tumugi::Plugin::GoogleCloudStorage::AtomicFile.new(path, fs).open(&block)
|
31
|
+
else
|
32
|
+
raise Tumugi::TumugiError.new('Invalid mode: #{mode}')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
path
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "tumugi-plugin-google_cloud_storage"
|
7
|
+
spec.version = "0.1.0"
|
8
|
+
spec.authors = ["Kazuyuki Honda"]
|
9
|
+
spec.email = ["hakobera@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Tumugi plugin for Google Cloud Storage"
|
12
|
+
spec.homepage = "https://github.com/tumugi/tumugi-plugin-google_cloud_storage"
|
13
|
+
spec.license = "Apache License Version 2.0"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = "exe"
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.required_ruby_version = '>= 2.1'
|
21
|
+
|
22
|
+
spec.add_runtime_dependency "tumugi", "~> 0.5.1"
|
23
|
+
spec.add_runtime_dependency "google-api-client", "~> 0.9.3"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "test-unit", "~> 3.1"
|
28
|
+
spec.add_development_dependency "test-unit-rr"
|
29
|
+
spec.add_development_dependency "coveralls"
|
30
|
+
spec.add_development_dependency "github_changelog_generator"
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tumugi-plugin-google_cloud_storage
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kazuyuki Honda
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tumugi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.5.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.5.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: google-api-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.9.3
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.9.3
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.11'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.11'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: test-unit
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.1'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.1'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: test-unit-rr
|
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
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: coveralls
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: github_changelog_generator
|
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'
|
125
|
+
description:
|
126
|
+
email:
|
127
|
+
- hakobera@gmail.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".gitignore"
|
133
|
+
- ".travis.yml"
|
134
|
+
- Gemfile
|
135
|
+
- README.md
|
136
|
+
- Rakefile
|
137
|
+
- bin/console
|
138
|
+
- bin/setup
|
139
|
+
- examples/example.rb
|
140
|
+
- examples/tumugi_config_example.rb
|
141
|
+
- lib/tumugi/plugin/google_cloud_storage/atomic_file.rb
|
142
|
+
- lib/tumugi/plugin/google_cloud_storage/file_system.rb
|
143
|
+
- lib/tumugi/plugin/target/google_cloud_storage_file.rb
|
144
|
+
- tumugi-plugin-google_cloud_storage.gemspec
|
145
|
+
homepage: https://github.com/tumugi/tumugi-plugin-google_cloud_storage
|
146
|
+
licenses:
|
147
|
+
- Apache License Version 2.0
|
148
|
+
metadata: {}
|
149
|
+
post_install_message:
|
150
|
+
rdoc_options: []
|
151
|
+
require_paths:
|
152
|
+
- lib
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '2.1'
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
requirements: []
|
164
|
+
rubyforge_project:
|
165
|
+
rubygems_version: 2.5.1
|
166
|
+
signing_key:
|
167
|
+
specification_version: 4
|
168
|
+
summary: Tumugi plugin for Google Cloud Storage
|
169
|
+
test_files: []
|