tumugi-plugin-google_drive 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 47062dacaeadccdc1a602bc81aa2cc4ca7291c59
4
+ data.tar.gz: 25690c27283aadbd29843ddd2bb6dcc59e3edbe4
5
+ SHA512:
6
+ metadata.gz: f5b8763001af3a4c6cc5a60872aed270cac5108695627be3d45057961910b4bb12800d9ba95d8dcc20c11fe98db67ff7201bbbabf550255f0991f906bf7fec16
7
+ data.tar.gz: 27706dd1077923a595ca29c28ae1030adc519a300c24862fa354204c828c45af2cc388ac0c9313061868b7eda7fcf2487674553542fb389e73d5993dc4909fd7
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .env
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 2.1
5
+ - 2.3.1
6
+ - jruby-9.1.2.0
7
+ before_install:
8
+ - gem install bundler
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in tumugi-plugin-google_drive.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,123 @@
1
+ [![Build Status](https://travis-ci.org/tumugi/tumugi-plugin-google_drive.svg?branch=master)](https://travis-ci.org/tumugi/tumugi-plugin-google_drive) [![Code Climate](https://codeclimate.com/github/tumugi/tumugi-plugin-google_drive/badges/gpa.svg)](https://codeclimate.com/github/tumugi/tumugi-plugin-google_drive) [![Coverage Status](https://coveralls.io/repos/github/tumugi/tumugi-plugin-google_drive/badge.svg?branch=master)](https://coveralls.io/github/tumugi/tumugi-plugin-google_drive?branch=master) [![Gem Version](https://badge.fury.io/rb/tumugi-plugin-google_drive.svg)](https://badge.fury.io/rb/tumugi-plugin-google_drive)
2
+
3
+ # tumugi-plugin-google_drive
4
+
5
+ [tumugi](https://github.com/tumugi/tumugi) plugin for Google Drive.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'tumugi-plugin-google_drive'
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_drive
25
+ ```
26
+
27
+ ## Component
28
+
29
+ ### Tumugi::Plugin::GoogleDriveFileTarget
30
+
31
+ This target represent file on Googl Drive.
32
+ This target has following parameters.
33
+
34
+ - name (required)
35
+ - Filename **string**
36
+ - file_id
37
+ - File ID **string**
38
+ - parents
39
+ - Parent folder ID **string** or **array of string**
40
+
41
+ Tumugi workflow file using this target is like this:
42
+
43
+ ```rb
44
+ task :task1 do
45
+ param :day, type: :time, auto_bind: true, required: true
46
+ output do
47
+ target(:google_drive_file,
48
+ name: "test_#{day.strftime('%Y%m%d')}.txt",
49
+ parents: "xyz")
50
+ end
51
+ run do
52
+ log 'task1#run'
53
+ output.open('w') {|f| f.puts('done') }
54
+ end
55
+ end
56
+ ```
57
+
58
+ ### Tumugi::Plugin::GoogleDriveFolderTarget
59
+
60
+ This target represent folder on Googl Drive.
61
+ This target has following parameters.
62
+
63
+ - name (required)
64
+ - Folder name **string**
65
+ - folder_id
66
+ - Folder ID **string**
67
+ - parents
68
+ - Parent folder ID **string** or **array of string**
69
+
70
+ ### Tumugi::Plugin::GoogleDriveFolderTask
71
+
72
+ This task create a folder on Googl Drive.
73
+ Tumugi workflow file using this task is like this:
74
+
75
+ ```rb
76
+ task :task1, type: :google_drive_folder do
77
+ param :day, type: :time, auto_bind: true, required: true
78
+ output do
79
+ target(:google_drive_folder,
80
+ name: "test_#{day.strftime('%Y%m%d')}.txt",
81
+ parents: "xyz")
82
+ end
83
+ end
84
+ ```
85
+
86
+ ### Config Section
87
+
88
+ tumugi-plugin-google_drive provide config section named "google_drive" which can specified Google Drive autenticaion info.
89
+
90
+ #### Authenticate by client_email and private_key
91
+
92
+ ```rb
93
+ Tumugi.config do |config|
94
+ config.section("google_drive") do |section|
95
+ section.project_id = "xxx"
96
+ section.client_email = "yyy@yyy.iam.gserviceaccount.com"
97
+ section.private_key = "zzz"
98
+ end
99
+ end
100
+ ```
101
+
102
+ #### Authenticate by JSON key file
103
+
104
+ ```rb
105
+ Tumugi.configure do |config|
106
+ config.section("google_drive") do |section|
107
+ section.private_key_file = "/path/to/key.json"
108
+ end
109
+ end
110
+ ```
111
+
112
+ ## Development
113
+
114
+ 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.
115
+
116
+ ## Contributing
117
+
118
+ Bug reports and pull requests are welcome on GitHub at https://github.com/tumugi/ttumugi-plugin-google_drive
119
+
120
+ ## License
121
+
122
+ The gem is available as open source under the terms of the [Apache License
123
+ Version 2.0](http://www.apache.org/licenses/).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "tumugi/plugin/google_drive"
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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,17 @@
1
+ task :task1 do
2
+ requires :folder
3
+ param :day, type: :time, auto_bind: true, required: true
4
+ output do
5
+ target(:google_drive_file,
6
+ name: "test_#{day.strftime('%Y%m%d')}.txt",
7
+ parents: input.folder_id)
8
+ end
9
+ run do
10
+ log 'task1#run'
11
+ output.open('w') {|f| f.puts('done') }
12
+ end
13
+ end
14
+
15
+ task :folder, type: :google_drive_folder do
16
+ param_set :name, 'xyz'
17
+ end
@@ -0,0 +1,7 @@
1
+ Tumugi.configure do |config|
2
+ config.section('google_drive') do |section|
3
+ section.project_id = ENV["PROJECT_ID"]
4
+ section.client_email = ENV["CLIENT_EMAIL"]
5
+ section.private_key = ENV["PRIVATE_KEY"].gsub(/\\n/, "\n")
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ require 'tumugi/atomic_file'
2
+
3
+ module Tumugi
4
+ module Plugin
5
+ module GoogleDrive
6
+ class AtomicFile < Tumugi::AtomicFile
7
+ attr_reader :id
8
+
9
+ def initialize(path, fs, file_id: nil, parents: nil)
10
+ super(path)
11
+ @fs = fs
12
+ @parents = parents
13
+ @id = (file_id.nil? ? @fs.generate_file_id : file_id)
14
+ end
15
+
16
+ def move_to_final_destination(temp_file)
17
+ @fs.upload(temp_file, path, file_id: @id, parents: @parents)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,194 @@
1
+ require 'google/apis/drive_v3'
2
+ require 'tumugi/error'
3
+
4
+ Tumugi::Config.register_section('google_drive', :project_id, :client_email, :private_key, :private_key_file)
5
+
6
+ module Tumugi
7
+ module Plugin
8
+ module GoogleDrive
9
+ class FileSystem
10
+
11
+ MIME_TYPE_FOLDER = 'application/vnd.google-apps.folder'
12
+
13
+ def initialize(config)
14
+ save_config(config)
15
+ end
16
+
17
+ def exist?(file_id)
18
+ client.get_file(file_id, options: request_options)
19
+ true
20
+ rescue => e
21
+ return false if e.respond_to?(:status_code) && e.status_code == 404
22
+ process_error(e)
23
+ end
24
+
25
+ def remove(file_id)
26
+ return unless exist?(file_id)
27
+
28
+ client.delete_file(file_id, options: request_options)
29
+ wait_until { !exist?(file_id) }
30
+ file_id
31
+ rescue
32
+ process_error($!)
33
+ end
34
+
35
+ def mkdir(name, folder_id: nil, parents: nil)
36
+ file_metadata = Google::Apis::DriveV3::File.new({
37
+ name: name,
38
+ mime_type: MIME_TYPE_FOLDER,
39
+ parents: parents,
40
+ id: folder_id
41
+ })
42
+ file = client.create_file(file_metadata, options: request_options)
43
+ wait_until { exist?(file.id) }
44
+ file
45
+ rescue
46
+ process_error($!)
47
+ end
48
+
49
+ def directory?(file_id)
50
+ file = client.get_file(file_id, options: request_options)
51
+ file.mime_type == MIME_TYPE_FOLDER
52
+ rescue
53
+ process_error($!)
54
+ end
55
+
56
+ def move(src_file_id, dest_name, dest_parents: nil)
57
+ file = copy(src_file_id, dest_name, dest_parents: dest_parents)
58
+ remove(src_file_id)
59
+ file
60
+ end
61
+
62
+ def copy(src_file_id, dest_name, dest_parents: nil)
63
+ dest_parents = [dest_parents] if dest_parents.is_a?(String)
64
+ dest_file_metadata = Google::Apis::DriveV3::File.new({
65
+ name: dest_name,
66
+ parents: dest_parents
67
+ })
68
+ file = client.copy_file(src_file_id, dest_file_metadata, options: request_options)
69
+ wait_until { exist?(file.id) }
70
+ file
71
+ rescue
72
+ process_error($!)
73
+ end
74
+
75
+ def upload(media, name, content_type: nil, file_id: nil, parents: nil)
76
+ parents = [parents] if parents.is_a?(String)
77
+ file_metadata = Google::Apis::DriveV3::File.new({
78
+ id: file_id,
79
+ name: name,
80
+ parents: parents
81
+ })
82
+ file = client.create_file(file_metadata, upload_source: media, content_type: content_type, options: request_options)
83
+ wait_until { exist?(file.id) }
84
+ file
85
+ rescue
86
+ process_error($!)
87
+ end
88
+
89
+ def put_string(contents, name, content_type: 'text/plain', file_id: nil, parents: nil)
90
+ media = StringIO.new(contents)
91
+ upload(media, name, content_type: content_type, file_id: file_id, parents: parents)
92
+ end
93
+
94
+ def download(file_id, download_path: nil, mode: 'r', &block)
95
+ if download_path.nil?
96
+ download_path = Tempfile.new('tumugi_google_drive_file_system').path
97
+ end
98
+ client.get_file(file_id, download_dest: download_path, options: request_options)
99
+ wait_until { File.exist?(download_path) }
100
+
101
+ if block_given?
102
+ File.open(download_path, mode, &block)
103
+ else
104
+ File.open(download_path, mode)
105
+ end
106
+ rescue
107
+ process_error($!)
108
+ end
109
+
110
+ def generate_file_id
111
+ client.generate_file_ids(count: 1, options: request_options).ids.first
112
+ rescue
113
+ process_error($!)
114
+ end
115
+
116
+ private
117
+
118
+ def save_config(config)
119
+ if config.private_key_file.nil?
120
+ @project_id = config.project_id
121
+ client_email = config.client_email
122
+ private_key = config.private_key
123
+ elsif config.private_key_file
124
+ json = JSON.parse(File.read(config.private_key_file))
125
+ @project_id = json['project_id']
126
+ client_email = json['client_email']
127
+ private_key = json['private_key']
128
+ end
129
+ @key = {
130
+ client_email: client_email,
131
+ private_key: private_key
132
+ }
133
+ end
134
+
135
+ def client
136
+ return @cached_client if @cached_client && @cached_client_expiration > Time.now
137
+
138
+ client = Google::Apis::DriveV3::DriveService.new
139
+ scope = Google::Apis::DriveV3::AUTH_DRIVE
140
+
141
+ if @key[:client_email] && @key[:private_key]
142
+ options = {
143
+ json_key_io: StringIO.new(JSON.generate(@key)),
144
+ scope: scope
145
+ }
146
+ auth = Google::Auth::ServiceAccountCredentials.make_creds(options)
147
+ else
148
+ auth = Google::Auth.get_application_default([scope])
149
+ end
150
+ auth.fetch_access_token!
151
+ client.authorization = auth
152
+
153
+ @cached_client_expiration = Time.now + (auth.expires_in / 2)
154
+ @cached_client = client
155
+ end
156
+
157
+ def wait_until(&block)
158
+ while not block.call
159
+ sleep 3
160
+ end
161
+ end
162
+
163
+ def process_error(err)
164
+ if err.respond_to?(:body)
165
+ begin
166
+ if err.body.nil?
167
+ reason = err.status_code.to_s
168
+ errors = "HTTP Status: #{err.status_code}\nHeaders: #{err.header.inspect}"
169
+ else
170
+ jobj = JSON.parse(err.body)
171
+ error = jobj["error"]
172
+ reason = error["errors"].map{|e| e["reason"]}.join(",")
173
+ errors = error["errors"].map{|e| e["message"] }.join("\n")
174
+ end
175
+ rescue JSON::ParserError
176
+ reason = err.status_code.to_s
177
+ errors = "HTTP Status: #{err.status_code}\nHeaders: #{err.header.inspect}\nBody:\n#{err.body}"
178
+ end
179
+ raise Tumugi::FileSystemError.new(errors, reason)
180
+ else
181
+ raise err
182
+ end
183
+ end
184
+
185
+ def request_options
186
+ {
187
+ retries: 5,
188
+ timeout_sec: 60
189
+ }
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,49 @@
1
+ require 'tumugi/config'
2
+ require 'tumugi/plugin'
3
+ require 'tumugi/plugin/file_system_target'
4
+ require 'tumugi/plugin/google_drive/atomic_file'
5
+ require 'tumugi/plugin/google_drive/file_system'
6
+
7
+ module Tumugi
8
+ module Plugin
9
+ class GoogleDriveFileTarget < Tumugi::Plugin::FileSystemTarget
10
+ Tumugi::Plugin.register_target('google_drive_file', self)
11
+
12
+ attr_reader :file_id, :name, :parents
13
+
14
+ def initialize(file_id: nil, name: nil, parents: nil, fs: nil)
15
+ @fs = fs unless fs.nil?
16
+ @file_id = file_id || self.fs.generate_file_id
17
+ @name = name
18
+ @parents = parents
19
+ super(@file_id)
20
+ end
21
+
22
+ def fs
23
+ @fs ||= Tumugi::Plugin::GoogleDrive::FileSystem.new(Tumugi.config.section('google_drive'))
24
+ end
25
+
26
+ def open(mode="r", &block)
27
+ if mode.include? 'r'
28
+ fs.download(file_id, mode: mode, &block)
29
+ elsif mode.include? 'w'
30
+ file = Tumugi::Plugin::GoogleDrive::AtomicFile.new(name, fs, file_id: @file_id, parents: @parents)
31
+ file.open(&block)
32
+ @file_id = file.id
33
+ else
34
+ raise Tumugi::TumugiError.new('Invalid mode: #{mode}')
35
+ end
36
+ end
37
+
38
+ def exist?
39
+ fs.exist?(file_id)
40
+ end
41
+
42
+ def to_s
43
+ s = "file_id: #{file_id}, name: #{name}"
44
+ s += ", parents: #{parents}" if parents
45
+ s
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,34 @@
1
+ require 'tumugi/config'
2
+ require 'tumugi/plugin'
3
+ require 'tumugi/plugin/google_drive/file_system'
4
+
5
+ module Tumugi
6
+ module Plugin
7
+ class GoogleDriveFolderTarget < Tumugi::Target
8
+ Tumugi::Plugin.register_target('google_drive_folder', self)
9
+
10
+ attr_reader :folder_id, :name, :parents
11
+
12
+ def initialize(folder_id: nil, name: nil, parents: nil, fs: nil)
13
+ @fs = fs unless fs.nil?
14
+ @folder_id = folder_id || self.fs.generate_file_id
15
+ @name = name
16
+ @parents = parents
17
+ end
18
+
19
+ def fs
20
+ @fs ||= Tumugi::Plugin::GoogleDrive::FileSystem.new(Tumugi.config.section('google_drive'))
21
+ end
22
+
23
+ def exist?
24
+ fs.exist?(folder_id)
25
+ end
26
+
27
+ def to_s
28
+ s = "folder_id: #{folder_id}, name: #{name}"
29
+ s += ", parents: #{parents}" if parents
30
+ s
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,27 @@
1
+ require 'tumugi'
2
+ require_relative '../target/google_drive_folder'
3
+
4
+ module Tumugi
5
+ module Plugin
6
+ class GoogleDriveFolderTask < Tumugi::Task
7
+ Tumugi::Plugin.register_task('google_drive_folder', self)
8
+
9
+ param :name, type: :string, required: true
10
+ param :folder_id, type: :string
11
+ param :parent, type: :string
12
+
13
+ def output
14
+ @output ||= Tumugi::Plugin::GoogleDriveFolderTarget.new(folder_id: folder_id, name: name, parents: parent.nil? ? nil : [parent])
15
+ end
16
+
17
+ def run
18
+ if output.exist?
19
+ log "skip: #{output} is already exists"
20
+ else
21
+ log "create folder: #{output}"
22
+ output.fs.mkdir(name, folder_id: output.folder_id, parents: output.parents)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ 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_drive"
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 Drive"
12
+ spec.homepage = "https://github.com/tumugi/tumugi-plugin-gcs"
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,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tumugi-plugin-google_drive
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-06-06 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/tumgui_config_example.rb
141
+ - lib/tumugi/plugin/google_drive/atomic_file.rb
142
+ - lib/tumugi/plugin/google_drive/file_system.rb
143
+ - lib/tumugi/plugin/target/google_drive_file.rb
144
+ - lib/tumugi/plugin/target/google_drive_folder.rb
145
+ - lib/tumugi/plugin/task/google_drive_folder.rb
146
+ - tumugi-plugin-google_drive.gemspec
147
+ homepage: https://github.com/tumugi/tumugi-plugin-gcs
148
+ licenses:
149
+ - Apache License Version 2.0
150
+ metadata: {}
151
+ post_install_message:
152
+ rdoc_options: []
153
+ require_paths:
154
+ - lib
155
+ required_ruby_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '2.1'
160
+ required_rubygems_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ requirements: []
166
+ rubyforge_project:
167
+ rubygems_version: 2.5.1
168
+ signing_key:
169
+ specification_version: 4
170
+ summary: Tumugi plugin for Google Drive
171
+ test_files: []