paperclip-gcs 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/README.md +217 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/paperclip-gcs.rb +1 -0
- data/lib/paperclip/gcs/version.rb +5 -0
- data/lib/paperclip/storage/gcs.rb +164 -0
- data/lib/paperclip/storage/gcs/bucket_repository.rb +25 -0
- data/lib/paperclip/storage/gcs/client_repository.rb +29 -0
- data/lib/paperclip/storage/gcs/credentials_resolver.rb +29 -0
- data/paperclip-gcs.gemspec +28 -0
- metadata +127 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1f1a924ccfce1e00e1528f8dd388dc410f4b9810
|
4
|
+
data.tar.gz: 1df9b5cc7b0ca186322ef4a3f02564bcf00ffa11
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 91ef9146b4d9c3531f8b19c0ff54a226a7ab3c6fd10cb6ca0735f8e13b5a5b31fafad1b94962dc2c2a46e9ca9b60b21b410a1063abdd6079bd15c1b69b2c3656
|
7
|
+
data.tar.gz: 42fd00c5d874ac04e83919f1b6cbb5c0751dc2b3df6936dd8f3dd4ca54918039503281ca3970c625b82cad98bc144d5bfffeb26b4735ed47c4eb17dd537a0aef
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
# paperclip-gcs
|
2
|
+
|
3
|
+
paperclip-gcs is a Paperclip storage driver for storing files in a Google Cloud Storage.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'paperclip-gcs'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
``` shell
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
``` shell
|
22
|
+
$ gem install paperclip-gcs
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
The GCS storage engine has been developed to work as similarly to S3 storage configuration as is possible. This gem can be configured in a Paperclip initializer as follows:
|
28
|
+
|
29
|
+
``` ruby
|
30
|
+
Paperclip::Attachment.default_options[:storage] = :gcs
|
31
|
+
Paperclip::Attachment.default_options[:gcs_bucket] = "your-bucket"
|
32
|
+
Paperclip::Attachment.default_options[:url] = ":gcs_path_url"
|
33
|
+
Paperclip::Attachment.default_options[:path] = ":class/:attachment/:id/:style/:filename"
|
34
|
+
Paperclip::Attachment.default_options[:gcs_credentials] = {
|
35
|
+
project: ENV["GCS_PROJECT"],
|
36
|
+
keyfile: ENV["GCS_KEYFILE"],
|
37
|
+
}
|
38
|
+
|
39
|
+
```
|
40
|
+
|
41
|
+
Or, at the level of the model such as in the following example:
|
42
|
+
|
43
|
+
``` ruby
|
44
|
+
has_attached_file :avatar,
|
45
|
+
storage: :gcs,
|
46
|
+
gcs_bucket: "your-bucket",
|
47
|
+
gcs_credentials: {
|
48
|
+
project: "your-project",
|
49
|
+
keyfile: "path/to/your/keyfile",
|
50
|
+
}
|
51
|
+
```
|
52
|
+
|
53
|
+
See also http://www.rubydoc.info/gems/paperclip/Paperclip/Storage/S3
|
54
|
+
|
55
|
+
## Configuration
|
56
|
+
|
57
|
+
### gcs_bucket
|
58
|
+
|
59
|
+
GCS bucket name.
|
60
|
+
|
61
|
+
### gcs_credentials
|
62
|
+
|
63
|
+
You can provide the project and credential information to connect to the Storage service, or if you are running on Google Compute Engine this configuration is taken care of for you.
|
64
|
+
|
65
|
+
#### project
|
66
|
+
|
67
|
+
Project identifier for GCS. Project are discovered in the following order:
|
68
|
+
|
69
|
+
* Specify project in `project`
|
70
|
+
* Discover project in environment variables `STORAGE_PROJECT`, `GOOGLE_CLOUD_PROJECT`, `GCLOUD_PROJECT`
|
71
|
+
* Discover GCE credentials
|
72
|
+
|
73
|
+
#### keyfile
|
74
|
+
|
75
|
+
Path of GCS service account credentials JSON file. Credentials are discovered in the following order:
|
76
|
+
|
77
|
+
* Specify credentials path in `keyfile`
|
78
|
+
* Discover credentials path in environment variables `GOOGLE_CLOUD_KEYFILE`, `GCLOUD_KEYFILE`
|
79
|
+
* Discover credentials JSON in environment variables `GOOGLE_CLOUD_KEYFILE_JSON`, `GCLOUD_KEYFILE_JSON`
|
80
|
+
* Discover credentials file in the Cloud SDK's path
|
81
|
+
* Discover GCE credentials
|
82
|
+
|
83
|
+
#### bucket (optional)
|
84
|
+
|
85
|
+
Here you can specify the GCS bucket name. If `gcs_bucket` also has a bucket specification, the value of` gcs_bucket` will be used.
|
86
|
+
|
87
|
+
### gcs_options
|
88
|
+
|
89
|
+
#### retries
|
90
|
+
|
91
|
+
Number of times to retry requests on server error.
|
92
|
+
|
93
|
+
#### timeout
|
94
|
+
|
95
|
+
Default timeout to use in requests.
|
96
|
+
|
97
|
+
### gcs_protocol
|
98
|
+
|
99
|
+
The protocol for the URLs generated to your GCS assets. Can be either 'http', 'https', or an empty string to generate protocol-relative URLs. Defaults to empty string.
|
100
|
+
|
101
|
+
### gcs_host_alias
|
102
|
+
|
103
|
+
The fully-qualified domain name (FQDN) that is the alias to the GCS domain of your bucket. Used with the :gcs_alias_url url interpolation. See the link in the url entry for more information about GCS domains and buckets.
|
104
|
+
|
105
|
+
### gcs_host_name
|
106
|
+
|
107
|
+
If you are using a bucket in a custom domain, write host_name.
|
108
|
+
|
109
|
+
### gcs_encryption_key
|
110
|
+
|
111
|
+
You can also choose to provide your own AES-256 key for server-side encryption. See also [Customer-supplied encryption keys](https://cloud.google.com/storage/docs/encryption#customer-supplied).
|
112
|
+
|
113
|
+
### gcs_metadata
|
114
|
+
|
115
|
+
User provided web-safe keys and arbitrary string values that will returned with requests for the file as "x-goog-meta-" response headers.
|
116
|
+
|
117
|
+
You can set metadata on a per style bases by doing the following:
|
118
|
+
|
119
|
+
``` ruby
|
120
|
+
gcs_metadata: {
|
121
|
+
thumb: { "foo" => "bar" }
|
122
|
+
}
|
123
|
+
```
|
124
|
+
|
125
|
+
Or globally:
|
126
|
+
|
127
|
+
``` ruby
|
128
|
+
gcs_metadata: { "foo" => "bar" }
|
129
|
+
```
|
130
|
+
|
131
|
+
### gcs_permissions
|
132
|
+
|
133
|
+
Permission for the object in GCS. Acceptable values are:
|
134
|
+
|
135
|
+
* `auth_read` - File owner gets OWNER access, and allAuthenticatedUsers get READER access.
|
136
|
+
* `owner_full` - File owner gets OWNER access, and project team owners get OWNER access.
|
137
|
+
* `owner_read` - File owner gets OWNER access, and project team owners get READER access.
|
138
|
+
* `private` - File owner gets OWNER access.
|
139
|
+
* `project_private` - File owner gets OWNER access, and project team members get access according to their roles.
|
140
|
+
* `public_read` - File owner gets OWNER access, and allUsers get READER access.
|
141
|
+
|
142
|
+
Default is nil (bucket default object ACL). See also [official document](https://cloud.google.com/storage/docs/access-control/lists).
|
143
|
+
|
144
|
+
You can set permissions on a per style bases by doing the following:
|
145
|
+
|
146
|
+
``` ruby
|
147
|
+
gcs_permissions: {
|
148
|
+
thumb: :public_read
|
149
|
+
}
|
150
|
+
```
|
151
|
+
|
152
|
+
Or globally:
|
153
|
+
|
154
|
+
``` ruby
|
155
|
+
gcs_permissions: :public_read
|
156
|
+
```
|
157
|
+
|
158
|
+
### gcs_storage_class
|
159
|
+
|
160
|
+
Storage class of the file. Acceptable values are:
|
161
|
+
|
162
|
+
* `dra` - Durable Reduced Availability
|
163
|
+
* `nearline` - Nearline Storage
|
164
|
+
* `coldline` - Coldline Storage
|
165
|
+
* `multi_regional` - Multi-Regional Storage
|
166
|
+
* `regional` - Regional Storage
|
167
|
+
* `standard` - Standard Storage
|
168
|
+
|
169
|
+
You can set storage class on a per style bases by doing the following:
|
170
|
+
|
171
|
+
``` ruby
|
172
|
+
gcs_storage_class: {
|
173
|
+
thumb: :multi_regional
|
174
|
+
}
|
175
|
+
```
|
176
|
+
|
177
|
+
Or globally:
|
178
|
+
|
179
|
+
``` ruby
|
180
|
+
gcs_storage_class: :multi_regional
|
181
|
+
```
|
182
|
+
|
183
|
+
### Interpolates
|
184
|
+
|
185
|
+
#### :gcs_alias_url
|
186
|
+
|
187
|
+
``` ruby
|
188
|
+
"#{attachment.gcs_protocol}//#{attachment.gcs_host_alias}/#{attachment.path(style)}"
|
189
|
+
```
|
190
|
+
|
191
|
+
#### :gcs_path_url
|
192
|
+
|
193
|
+
``` ruby
|
194
|
+
"#{attachment.gcs_protocol}//#{attachment.gcs_host_name}/#{attachment.gcs_bucket_name}/#{attachment.path(style)}"
|
195
|
+
```
|
196
|
+
|
197
|
+
#### :gcs_domain_url
|
198
|
+
|
199
|
+
``` ruby
|
200
|
+
"#{attachment.gcs_protocol}//#{attachment.gcs_bucket_name}.#{attachment.gcs_host_name}/#{attachment.path(style)}"
|
201
|
+
```
|
202
|
+
|
203
|
+
#### :asset_host
|
204
|
+
|
205
|
+
``` ruby
|
206
|
+
"#{attachment.path(style)}"
|
207
|
+
```
|
208
|
+
|
209
|
+
## Development
|
210
|
+
|
211
|
+
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.
|
212
|
+
|
213
|
+
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).
|
214
|
+
|
215
|
+
## Contributing
|
216
|
+
|
217
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/daichirata/paperclip-gcs.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "paperclip/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(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "paperclip/storage/gcs"
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require "google-cloud-storage"
|
2
|
+
|
3
|
+
require "paperclip/gcs/version"
|
4
|
+
require "paperclip/storage/gcs/bucket_repository"
|
5
|
+
require "paperclip/storage/gcs/client_repository"
|
6
|
+
require "paperclip/storage/gcs/credentials_resolver"
|
7
|
+
|
8
|
+
module Paperclip
|
9
|
+
module Storage
|
10
|
+
module Gcs
|
11
|
+
DEFAULT_GCS_HOST_NAME = "storage.googleapis.com"
|
12
|
+
|
13
|
+
def self.extended(base)
|
14
|
+
base.instance_eval do
|
15
|
+
@gcs_options = @options[:gcs_options] || {}
|
16
|
+
@gcs_credentials = @options[:gcs_credentials]
|
17
|
+
@gcs_bucket_name = @options[:gcs_bucket]
|
18
|
+
@gcs_protocol = @options[:gcs_protocol]
|
19
|
+
@gcs_host_alias = @options[:gcs_host_alias]
|
20
|
+
@gcs_host_name = @options[:gcs_host_name]
|
21
|
+
@gcs_encryption_key = @options[:gcs_encryption_key]
|
22
|
+
@gcs_metadata = normalize_style(@options[:gcs_metadata])
|
23
|
+
@gcs_permissions = normalize_style(@options[:gcs_permissions])
|
24
|
+
@gcs_storage_class = normalize_style(@options[:gcs_storage_class])
|
25
|
+
|
26
|
+
unless @options[:url].to_s.match(%r{\A:gcs_(alias|path|domain)_url\z}) || @options[:url] == ":asset_host".freeze
|
27
|
+
@options[:path] = path_option.gsub(/:url/, @options[:url]).sub(%r{\A:rails_root/public/system}, "".freeze)
|
28
|
+
@options[:url] = ":gcs_path_url".freeze
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Paperclip.interpolates(:gcs_alias_url) do |attachment, style|
|
33
|
+
"#{attachment.gcs_protocol}//#{attachment.gcs_host_alias}/#{attachment.path(style)}"
|
34
|
+
end unless Paperclip::Interpolations.respond_to?(:gcs_alias_url)
|
35
|
+
|
36
|
+
Paperclip.interpolates(:gcs_path_url) do |attachment, style|
|
37
|
+
"#{attachment.gcs_protocol}//#{attachment.gcs_host_name}/#{attachment.gcs_bucket_name}/#{attachment.path(style)}"
|
38
|
+
end unless Paperclip::Interpolations.respond_to?(:gcs_path_url)
|
39
|
+
|
40
|
+
Paperclip.interpolates(:gcs_domain_url) do |attachment, style|
|
41
|
+
"#{attachment.gcs_protocol}//#{attachment.gcs_bucket_name}.#{attachment.gcs_host_name}/#{attachment.path(style)}"
|
42
|
+
end unless Paperclip::Interpolations.respond_to?(:gcs_domain_url)
|
43
|
+
|
44
|
+
Paperclip.interpolates(:asset_host) do |attachment, style|
|
45
|
+
"#{attachment.path(style)}"
|
46
|
+
end unless Paperclip::Interpolations.respond_to?(:asset_host)
|
47
|
+
end
|
48
|
+
|
49
|
+
def expiring_url(time = 3600, style = default_style)
|
50
|
+
if file_path = path(style)
|
51
|
+
gcs_bucket.signed_url(file_path, expires: time)
|
52
|
+
else
|
53
|
+
url(style)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def exists?(style = default_style)
|
58
|
+
if original_filename
|
59
|
+
gcs_bucket.find_file(path(style))
|
60
|
+
else
|
61
|
+
false
|
62
|
+
end
|
63
|
+
rescue Google::Cloud::Error
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def flush_writes
|
68
|
+
@queued_for_write.each do |style, file|
|
69
|
+
log("saving #{path(style)}")
|
70
|
+
|
71
|
+
opts = {
|
72
|
+
content_type: file.content_type,
|
73
|
+
encryption_key: gcs_encryption_key,
|
74
|
+
acl: gcs_permissions(style),
|
75
|
+
storage_class: gcs_storage_class(style),
|
76
|
+
metadata: gcs_metadata(style),
|
77
|
+
}
|
78
|
+
gcs_bucket.upload_file(file.path, path(style), opts)
|
79
|
+
end
|
80
|
+
after_flush_writes
|
81
|
+
@queued_for_write = {}
|
82
|
+
end
|
83
|
+
|
84
|
+
def flush_deletes
|
85
|
+
@queued_for_delete.each do |path|
|
86
|
+
begin
|
87
|
+
log("deleting #{path}")
|
88
|
+
|
89
|
+
gcs_bucket.file(path).delete
|
90
|
+
rescue Google::Cloud::Error
|
91
|
+
# Ignore this.
|
92
|
+
end
|
93
|
+
end
|
94
|
+
@queued_for_delete = []
|
95
|
+
end
|
96
|
+
|
97
|
+
def copy_to_local_file(style, local_dest_path)
|
98
|
+
log("copying #{path(style)} to local file #{local_dest_path}")
|
99
|
+
|
100
|
+
gcs_bucket.file(path(style)).download(local_dest_path, encryption_key: gcs_encryption_key)
|
101
|
+
rescue Google::Cloud::Error => e
|
102
|
+
warn("#{e} - cannot copy #{path(style)} to local file #{local_dest_path}")
|
103
|
+
false
|
104
|
+
end
|
105
|
+
|
106
|
+
def gcs_protocol
|
107
|
+
unwrap_proc(@gcs_protocol, self)
|
108
|
+
end
|
109
|
+
|
110
|
+
def gcs_host_alias
|
111
|
+
unwrap_proc(@gcs_host_alias, self)
|
112
|
+
end
|
113
|
+
|
114
|
+
def gcs_host_name
|
115
|
+
unwrap_proc(@gcs_host_name, self) || DEFAULT_GCS_HOST_NAME
|
116
|
+
end
|
117
|
+
|
118
|
+
def gcs_bucket_name
|
119
|
+
(unwrap_proc(@gcs_bucket_name, self) || gcs_credentials[:bucket]) or
|
120
|
+
raise ArgumentError, "missing required :gcs_bucket option"
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def normalize_style(opts)
|
126
|
+
opts = { default: opts } unless opts.respond_to?(:merge)
|
127
|
+
opts.merge(default: opts[:default])
|
128
|
+
end
|
129
|
+
|
130
|
+
def unwrap_proc(obj, *args)
|
131
|
+
obj.respond_to?(:call) ? obj.call(*args) : obj
|
132
|
+
end
|
133
|
+
|
134
|
+
def gcs_encryption_key
|
135
|
+
unwrap_proc(@gcs_encryption_key, self)
|
136
|
+
end
|
137
|
+
|
138
|
+
def gcs_permissions(style = default_style)
|
139
|
+
unwrap_proc(@gcs_permissions[style] || @gcs_permissions[:default], self, style)
|
140
|
+
end
|
141
|
+
|
142
|
+
def gcs_storage_class(style = default_style)
|
143
|
+
unwrap_proc(@gcs_storage_class[style] || @gcs_storage_class[:default], self, style)
|
144
|
+
end
|
145
|
+
|
146
|
+
def gcs_metadata(style = default_style)
|
147
|
+
unwrap_proc(@gcs_metadata[style] || @gcs_metadata[:default], self, style)
|
148
|
+
end
|
149
|
+
|
150
|
+
def gcs_credentials
|
151
|
+
@_gcs_credentials ||= CredentialsResolver.resolve(unwrap_proc(@gcs_credentials, self))
|
152
|
+
end
|
153
|
+
|
154
|
+
def gcs_client
|
155
|
+
@_gcs_client ||= ClientRepository.find(gcs_credentials.slice(:project, :keyfile).merge(
|
156
|
+
@gcs_options.slice(:scope, :retries, :timeout)))
|
157
|
+
end
|
158
|
+
|
159
|
+
def gcs_bucket
|
160
|
+
@_gcs_bucket ||= BucketRepository.find(gcs_client, gcs_bucket_name)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Paperclip
|
2
|
+
module Storage
|
3
|
+
module Gcs
|
4
|
+
class BucketRepository
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
CACHE_KEY = self.class.name.freeze
|
8
|
+
|
9
|
+
def self.find(client, bucket_name)
|
10
|
+
instance.find(client, bucket_name)
|
11
|
+
end
|
12
|
+
|
13
|
+
def find(client, bucket_name)
|
14
|
+
buckets[[client, bucket_name]] ||= client.bucket(bucket_name)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def buckets
|
20
|
+
Thread.current[CACHE_KEY] ||= {}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Paperclip
|
2
|
+
module Storage
|
3
|
+
module Gcs
|
4
|
+
class ClientRepository
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
CACHE_KEY = self.class.name.freeze
|
8
|
+
|
9
|
+
def self.find(config)
|
10
|
+
instance.find(config)
|
11
|
+
end
|
12
|
+
|
13
|
+
def find(config)
|
14
|
+
clients[config] ||= Google::Cloud.storage(
|
15
|
+
config[:project],
|
16
|
+
config[:keyfile],
|
17
|
+
config.slice(:scope, :retries, :timeout)
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def clients
|
24
|
+
Thread.current[CACHE_KEY] ||= {}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Paperclip
|
2
|
+
module Storage
|
3
|
+
module Gcs
|
4
|
+
module CredentialsResolver
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def resolve(credentials)
|
8
|
+
cred = case credentials
|
9
|
+
when File
|
10
|
+
YAML.load(ERB.new(File.read(credentials.path)).result)
|
11
|
+
when String, Pathname
|
12
|
+
YAML.load(ERB.new(File.read(credentials)).result)
|
13
|
+
when Hash
|
14
|
+
credentials
|
15
|
+
when NilClass
|
16
|
+
{}
|
17
|
+
else
|
18
|
+
raise ArgumentError, ":gcs_credentials is not a path, file, nor a hash"
|
19
|
+
end
|
20
|
+
(cred.stringify_keys[env] || cred).symbolize_keys
|
21
|
+
end
|
22
|
+
|
23
|
+
def env
|
24
|
+
(defined?(Rails) ? Rails.env : nil).to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "paperclip/gcs/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "paperclip-gcs"
|
8
|
+
spec.version = Paperclip::Gcs::VERSION
|
9
|
+
spec.authors = ["Daichi HIRATA"]
|
10
|
+
spec.email = ["daichirata@gmail.com"]
|
11
|
+
spec.summary = "Extends Paperclip with Google Cloud Storage"
|
12
|
+
spec.description = "Extends Paperclip with Google Cloud Storage"
|
13
|
+
spec.homepage = "https://github.com/daichirata/paperclip-gcs"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
16
|
+
f.match(%r{^(test|spec|features)/})
|
17
|
+
end
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_runtime_dependency "paperclip", ">= 4.0"
|
23
|
+
spec.add_runtime_dependency "google-cloud-storage", "~> 1.0"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.15"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: paperclip-gcs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daichi HIRATA
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-06-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: paperclip
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: google-cloud-storage
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
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.15'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.15'
|
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: minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '5.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '5.0'
|
83
|
+
description: Extends Paperclip with Google Cloud Storage
|
84
|
+
email:
|
85
|
+
- daichirata@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".travis.yml"
|
92
|
+
- Gemfile
|
93
|
+
- README.md
|
94
|
+
- Rakefile
|
95
|
+
- bin/console
|
96
|
+
- bin/setup
|
97
|
+
- lib/paperclip-gcs.rb
|
98
|
+
- lib/paperclip/gcs/version.rb
|
99
|
+
- lib/paperclip/storage/gcs.rb
|
100
|
+
- lib/paperclip/storage/gcs/bucket_repository.rb
|
101
|
+
- lib/paperclip/storage/gcs/client_repository.rb
|
102
|
+
- lib/paperclip/storage/gcs/credentials_resolver.rb
|
103
|
+
- paperclip-gcs.gemspec
|
104
|
+
homepage: https://github.com/daichirata/paperclip-gcs
|
105
|
+
licenses: []
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 2.5.1
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: Extends Paperclip with Google Cloud Storage
|
127
|
+
test_files: []
|