sndacs 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +0 -2
- data/README.rdoc +21 -3
- data/lib/sndacs/bucket.rb +100 -52
- data/lib/sndacs/buckets_extension.rb +5 -0
- data/lib/sndacs/config.rb +59 -0
- data/lib/sndacs/connection.rb +38 -13
- data/lib/sndacs/exceptions.rb +6 -3
- data/lib/sndacs/object.rb +35 -24
- data/lib/sndacs/objects_extension.rb +2 -0
- data/lib/sndacs/parser.rb +31 -8
- data/lib/sndacs/request.rb +8 -1
- data/lib/sndacs/service.rb +38 -27
- data/lib/sndacs/signature.rb +6 -31
- data/lib/sndacs/version.rb +1 -1
- data/lib/sndacs.rb +28 -2
- data/sndacs.gemspec +5 -5
- data/spec/sndacs/bucket_spec.rb +180 -0
- data/spec/sndacs/object_spec.rb +167 -0
- data/spec/sndacs/service_spec.rb +30 -19
- data/spec/spec_helper.rb +19 -0
- metadata +90 -66
- data/test/bucket_test.rb +0 -215
- data/test/connection_test.rb +0 -214
- data/test/object_test.rb +0 -205
- data/test/service_test.rb +0 -111
- data/test/signature_test.rb +0 -205
- data/test/test_helper.rb +0 -3
data/lib/sndacs/object.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Sndacs
|
2
2
|
|
3
|
-
# Class responsible for handling objects stored in
|
3
|
+
# Class responsible for handling objects stored in CS buckets
|
4
4
|
class Object
|
5
5
|
include Parser
|
6
6
|
extend Forwardable
|
@@ -10,7 +10,7 @@ module Sndacs
|
|
10
10
|
attr_writer :content
|
11
11
|
|
12
12
|
def_instance_delegators :bucket, :name, :service, :bucket_request, :vhost?, :host, :path_prefix
|
13
|
-
def_instance_delegators :service, :protocol, :port, :secret_access_key
|
13
|
+
def_instance_delegators :service, :protocol, :port, :access_key_id, :secret_access_key
|
14
14
|
private_class_method :new
|
15
15
|
|
16
16
|
# Compares the object with other object. Returns true if the key
|
@@ -57,30 +57,24 @@ module Sndacs
|
|
57
57
|
# to do it).
|
58
58
|
def retrieve
|
59
59
|
object_headers
|
60
|
-
self
|
61
|
-
end
|
62
60
|
|
63
|
-
|
64
|
-
# exists or false otherwise. Uses #retrieve method, but catches
|
65
|
-
# S3::Error::NoSuchKey exception and returns false when it happens
|
66
|
-
def exists?
|
67
|
-
retrieve
|
68
|
-
true
|
69
|
-
rescue Error::NoSuchKey
|
70
|
-
false
|
61
|
+
self
|
71
62
|
end
|
72
63
|
|
73
64
|
# Downloads the content of the object, and caches it. Pass true to
|
74
65
|
# clear the cache and download the object again.
|
75
66
|
def content(reload = false)
|
76
67
|
return @content if defined?(@content) and not reload
|
68
|
+
|
77
69
|
get_object
|
70
|
+
|
78
71
|
@content
|
79
72
|
end
|
80
73
|
|
81
74
|
# Saves the object, returns true if successfull.
|
82
75
|
def save
|
83
76
|
put_object
|
77
|
+
|
84
78
|
true
|
85
79
|
end
|
86
80
|
|
@@ -89,7 +83,7 @@ module Sndacs
|
|
89
83
|
# ==== Options
|
90
84
|
# * <tt>:key</tt> - New key to store object in
|
91
85
|
# * <tt>:bucket</tt> - New bucket to store object in (instance of
|
92
|
-
#
|
86
|
+
# Sndacs::Bucket)
|
93
87
|
# * <tt>:acl</tt> - ACL of the copied object (default:
|
94
88
|
# "public-read")
|
95
89
|
# * <tt>:content_type</tt> - Content type of the copied object
|
@@ -101,40 +95,53 @@ module Sndacs
|
|
101
95
|
# Destroys the file on the server
|
102
96
|
def destroy
|
103
97
|
delete_object
|
98
|
+
|
104
99
|
true
|
105
100
|
end
|
106
101
|
|
107
102
|
# Returns Object's URL using protocol specified in service,
|
108
|
-
# e.g. <tt>http://
|
103
|
+
# e.g. <tt>http://storage.grandcloud.cn/bucket/key/file.extension</tt>
|
109
104
|
def url
|
110
105
|
URI.escape("#{protocol}#{host}/#{path_prefix}#{key}")
|
111
106
|
end
|
112
107
|
|
108
|
+
# Returns Object's CNAME URL (without <tt>storage.grandcloud.cn</tt>
|
109
|
+
# suffix) using protocol specified in Service,
|
110
|
+
# e.g. <tt>http://domain.com/key/with/path.extension</tt>. (you
|
111
|
+
# have to set the CNAME in your DNS before using the CNAME URL
|
112
|
+
# schema).
|
113
|
+
def cname_url
|
114
|
+
URI.escape("#{protocol}#{name}/#{key}") if bucket.vhost?
|
115
|
+
end
|
116
|
+
|
113
117
|
# Returns a temporary url to the object that expires on the
|
114
|
-
# timestamp given. Defaults to
|
118
|
+
# timestamp given. Defaults to 5min expire time.
|
115
119
|
def temporary_url(expires_at = Time.now + 3600)
|
120
|
+
url = URI.escape("#{protocol}#{host(true)}/#{path_prefix}#{key}")
|
116
121
|
signature = Signature.generate_temporary_url_signature(:bucket => name,
|
117
122
|
:resource => key,
|
118
123
|
:expires_at => expires_at,
|
119
124
|
:secret_access_key => secret_access_key)
|
120
125
|
|
121
|
-
"#{url}?
|
126
|
+
"#{url}?SNDAAccessKeyId=#{access_key_id}&Expires=#{expires_at.to_i.to_s}&Signature=#{signature}"
|
122
127
|
end
|
123
128
|
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
129
|
+
# Retrieves the object from the server, returns true if the object
|
130
|
+
# exists or false otherwise. Uses #retrieve method, but catches
|
131
|
+
# Sndacs::Error::NoSuchKey exception and returns false when it happens
|
132
|
+
def exists?
|
133
|
+
retrieve
|
134
|
+
|
135
|
+
true
|
136
|
+
rescue Error::NoSuchKey
|
137
|
+
false
|
131
138
|
end
|
132
139
|
|
133
140
|
def inspect #:nodoc:
|
134
141
|
"#<#{self.class}:/#{name}/#{key}>"
|
135
142
|
end
|
136
143
|
|
137
|
-
|
144
|
+
private
|
138
145
|
|
139
146
|
attr_writer :last_modified, :etag, :size, :original_key, :bucket
|
140
147
|
|
@@ -171,11 +178,13 @@ module Sndacs
|
|
171
178
|
|
172
179
|
def get_object(options = {})
|
173
180
|
response = object_request(:get, options)
|
181
|
+
|
174
182
|
parse_headers(response)
|
175
183
|
end
|
176
184
|
|
177
185
|
def object_headers(options = {})
|
178
186
|
response = object_request(:head, options)
|
187
|
+
|
179
188
|
parse_headers(response)
|
180
189
|
rescue Error::ResponseError => e
|
181
190
|
if e.response.code.to_i == 404
|
@@ -187,6 +196,7 @@ module Sndacs
|
|
187
196
|
|
188
197
|
def put_object
|
189
198
|
response = object_request(:put, :body => content, :headers => dump_headers)
|
199
|
+
|
190
200
|
parse_headers(response)
|
191
201
|
end
|
192
202
|
|
@@ -250,4 +260,5 @@ module Sndacs
|
|
250
260
|
end
|
251
261
|
end
|
252
262
|
end
|
263
|
+
|
253
264
|
end
|
data/lib/sndacs/parser.rb
CHANGED
@@ -1,25 +1,36 @@
|
|
1
1
|
require 'rexml/document'
|
2
2
|
|
3
3
|
module Sndacs
|
4
|
+
|
4
5
|
module Parser
|
5
6
|
include REXML
|
6
7
|
|
7
8
|
def rexml_document(xml)
|
8
9
|
xml.force_encoding(::Encoding::UTF_8) if xml.respond_to? :force_encoding
|
10
|
+
|
9
11
|
Document.new(xml)
|
10
12
|
end
|
11
13
|
|
12
|
-
def
|
13
|
-
|
14
|
-
rexml_document(xml).elements.each("ListAllMyBucketsResult/Buckets/Bucket
|
15
|
-
|
16
|
-
|
14
|
+
def parse_all_buckets_result(xml)
|
15
|
+
all_buckets = []
|
16
|
+
rexml_document(xml).elements.each("ListAllMyBucketsResult/Buckets/Bucket") do |e|
|
17
|
+
bucket_attributes = {}
|
18
|
+
bucket_attributes[:name] = e.elements["Name"].text
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
+
element_location = e.elements["Location"]
|
21
|
+
if element_location
|
22
|
+
bucket_attributes[:location] = element_location.text
|
23
|
+
else
|
24
|
+
bucket_attributes[:location] = REGION_DEFAULT
|
25
|
+
end
|
26
|
+
|
27
|
+
all_buckets << bucket_attributes
|
28
|
+
end
|
29
|
+
|
30
|
+
all_buckets
|
20
31
|
end
|
21
32
|
|
22
|
-
def
|
33
|
+
def parse_all_objects_result(xml)
|
23
34
|
objects_attributes = []
|
24
35
|
rexml_document(xml).elements.each("ListBucketResult/Contents") do |e|
|
25
36
|
object_attributes = {}
|
@@ -27,11 +38,22 @@ module Sndacs
|
|
27
38
|
object_attributes[:etag] = e.elements["ETag"].text
|
28
39
|
object_attributes[:last_modified] = e.elements["LastModified"].text
|
29
40
|
object_attributes[:size] = e.elements["Size"].text
|
41
|
+
|
30
42
|
objects_attributes << object_attributes
|
31
43
|
end
|
44
|
+
|
32
45
|
objects_attributes
|
33
46
|
end
|
34
47
|
|
48
|
+
def parse_location_constraint(xml)
|
49
|
+
location = rexml_document(xml).elements["LocationConstraint"].text
|
50
|
+
if location.nil? || location == ''
|
51
|
+
location = REGION_DEFAULT
|
52
|
+
end
|
53
|
+
|
54
|
+
location
|
55
|
+
end
|
56
|
+
|
35
57
|
def parse_copy_object_result(xml)
|
36
58
|
object_attributes = {}
|
37
59
|
document = rexml_document(xml)
|
@@ -51,4 +73,5 @@ module Sndacs
|
|
51
73
|
rexml_document(xml).elements["ListBucketResult/IsTruncated"].text =='true'
|
52
74
|
end
|
53
75
|
end
|
76
|
+
|
54
77
|
end
|
data/lib/sndacs/request.rb
CHANGED
@@ -1,25 +1,31 @@
|
|
1
1
|
module Sndacs
|
2
|
+
|
2
3
|
# Class responsible for sending chunked requests
|
3
4
|
# properly. Net::HTTPGenericRequest has hardcoded chunk_size, so we
|
4
5
|
# inherit the class and override chunk_size.
|
5
6
|
class Request < Net::HTTPGenericRequest
|
6
7
|
def initialize(chunk_size, m, reqbody, resbody, path, initheader = nil)
|
7
8
|
@chunk_size = chunk_size
|
9
|
+
|
8
10
|
super(m, reqbody, resbody, path, initheader)
|
9
11
|
end
|
10
12
|
|
11
|
-
|
13
|
+
private
|
12
14
|
|
13
15
|
def send_request_with_body_stream(sock, ver, path, f)
|
14
16
|
unless content_length() or chunked?
|
15
17
|
raise ArgumentError, "Content-Length not given and Transfer-Encoding is not `chunked'"
|
16
18
|
end
|
19
|
+
|
17
20
|
supply_default_content_type
|
21
|
+
|
18
22
|
write_header sock, ver, path
|
23
|
+
|
19
24
|
if chunked?
|
20
25
|
while s = f.read(@chunk_size)
|
21
26
|
sock.write(sprintf("%x\r\n", s.length) << s << "\r\n")
|
22
27
|
end
|
28
|
+
|
23
29
|
sock.write "0\r\n\r\n"
|
24
30
|
else
|
25
31
|
while s = f.read(@chunk_size)
|
@@ -28,4 +34,5 @@ module Sndacs
|
|
28
34
|
end
|
29
35
|
end
|
30
36
|
end
|
37
|
+
|
31
38
|
end
|
data/lib/sndacs/service.rb
CHANGED
@@ -3,15 +3,16 @@ require 'net/http'
|
|
3
3
|
require 'proxies'
|
4
4
|
|
5
5
|
require 'sndacs/parser'
|
6
|
-
require 'sndacs/buckets_extension'
|
7
6
|
require 'sndacs/connection'
|
7
|
+
require 'sndacs/buckets_extension'
|
8
8
|
|
9
9
|
module Sndacs
|
10
|
+
|
10
11
|
class Service
|
11
12
|
include Parser
|
12
13
|
include Proxies
|
13
14
|
|
14
|
-
attr_reader :access_key_id, :secret_access_key, :
|
15
|
+
attr_reader :access_key_id, :secret_access_key, :proxy , :use_ssl
|
15
16
|
|
16
17
|
# Compares service to other, by <tt>access_key_id</tt> and
|
17
18
|
# <tt>secret_access_key</tt>
|
@@ -30,28 +31,28 @@ module Sndacs
|
|
30
31
|
# (false by default)
|
31
32
|
# * <tt>:timeout</tt> - Timeout to use by the Net::HTTP object
|
32
33
|
# (60 by default)
|
33
|
-
def initialize(options)
|
34
|
-
@access_key_id = options.fetch(:access_key_id)
|
35
|
-
@secret_access_key = options.fetch(:secret_access_key)
|
36
|
-
@
|
37
|
-
@timeout = options.fetch(:timeout,
|
38
|
-
@
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
def initialize(options = {})
|
35
|
+
@access_key_id = options.fetch(:access_key_id, Config.access_key_id)
|
36
|
+
@secret_access_key = options.fetch(:secret_access_key, Config.secret_access_key)
|
37
|
+
@proxy = options.fetch(:proxy, Config.proxy)
|
38
|
+
@timeout = options.fetch(:timeout, Config.timeout)
|
39
|
+
@use_ssl = options.fetch(:use_ssl, Config.use_ssl)
|
40
|
+
@debug = options.fetch(:debug, Config.debug)
|
41
|
+
|
42
|
+
raise ArgumentError, "Wrong proxy settings. Must specify at least :host option." if @proxy && !@proxy[:host]
|
42
43
|
end
|
43
44
|
|
44
45
|
# Returns all buckets in the service and caches the result (see
|
45
46
|
# +reload+)
|
46
47
|
def buckets
|
47
|
-
Proxy.new(lambda {
|
48
|
+
Proxy.new(lambda { buckets_all }, :owner => self, :extend => BucketsExtension)
|
48
49
|
end
|
49
50
|
|
50
|
-
# Returns the bucket with the given name. Does not check whether the
|
51
|
+
# Returns the bucket with the given name and region. Does not check whether the
|
51
52
|
# bucket exists. But also does not issue any HTTP requests, so it's
|
52
53
|
# much faster than buckets.find
|
53
|
-
def bucket(name)
|
54
|
-
Bucket.send(:new, self, name)
|
54
|
+
def bucket(name, region = nil)
|
55
|
+
Bucket.send(:new, self, name, region || REGION_DEFAULT)
|
55
56
|
end
|
56
57
|
|
57
58
|
# Returns "http://" or "https://", depends on <tt>:use_ssl</tt>
|
@@ -70,26 +71,36 @@ module Sndacs
|
|
70
71
|
"#<#{self.class}:#@access_key_id>"
|
71
72
|
end
|
72
73
|
|
73
|
-
|
74
|
+
private
|
74
75
|
|
75
|
-
def
|
76
|
+
def buckets_all
|
76
77
|
response = service_request(:get)
|
77
|
-
|
78
|
-
|
78
|
+
|
79
|
+
all_buckets = parse_all_buckets_result(response.body)
|
80
|
+
all_buckets.map { |bucket| Bucket.send(:new, self, bucket[:name], bucket[:region]) }
|
79
81
|
end
|
80
82
|
|
81
83
|
def service_request(method, options = {})
|
82
|
-
|
84
|
+
unless options[:path]
|
85
|
+
options[:path] = '/'
|
86
|
+
end
|
87
|
+
|
88
|
+
req_path = options[:path]
|
89
|
+
if req_path[0,1] != '/'
|
90
|
+
req_path = "/#{req_path}"
|
91
|
+
end
|
92
|
+
|
93
|
+
connection.request(method, options.merge(:path => req_path))
|
83
94
|
end
|
84
95
|
|
85
96
|
def connection
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
:proxy => @proxy)
|
97
|
+
@connection ||= Connection.new(:access_key_id => @access_key_id,
|
98
|
+
:secret_access_key => @secret_access_key,
|
99
|
+
:use_ssl => @use_ssl,
|
100
|
+
:timeout => @timeout,
|
101
|
+
:proxy => @proxy,
|
102
|
+
:debug => @debug)
|
93
103
|
end
|
94
104
|
end
|
105
|
+
|
95
106
|
end
|
data/lib/sndacs/signature.rb
CHANGED
@@ -2,11 +2,11 @@ module Sndacs
|
|
2
2
|
|
3
3
|
# Class responsible for generating signatures to requests.
|
4
4
|
#
|
5
|
-
# Implements algorithm defined by
|
5
|
+
# Implements algorithm defined by GrandCloud Web Services to sign
|
6
6
|
# request with secret private credentials
|
7
7
|
#
|
8
8
|
# === See
|
9
|
-
#
|
9
|
+
# https://cs-console.grandcloud.cn/public/docs/GrandCloud_Storage_Developer_Guide.pdf
|
10
10
|
|
11
11
|
class Signature
|
12
12
|
|
@@ -62,34 +62,7 @@ module Sndacs
|
|
62
62
|
CGI.escape(signature)
|
63
63
|
end
|
64
64
|
|
65
|
-
|
66
|
-
#
|
67
|
-
# ==== Options
|
68
|
-
# * <tt>:bucket</tt> - Bucket in which the resource resides
|
69
|
-
# * <tt>:resource</tt> - Path to the resouce you want to create
|
70
|
-
# a temporary link to
|
71
|
-
# * <tt>:access_key</tt> - Access key
|
72
|
-
# * <tt>:secret_access_key</tt> - Secret access key
|
73
|
-
# * <tt>:expires_at</tt> - Unix time stamp of when the resouce
|
74
|
-
# link will expire
|
75
|
-
# * <tt>:method</tt> - HTTP request method you want to use on
|
76
|
-
# the resource, defaults to GET
|
77
|
-
# * <tt>:headers</tt> - Any additional HTTP headers you intend
|
78
|
-
# to use when requesting the resource
|
79
|
-
def self.generate_temporary_url(options)
|
80
|
-
bucket = options[:bucket]
|
81
|
-
resource = options[:resource]
|
82
|
-
access_key = options[:access_key]
|
83
|
-
expires = options[:expires_at].to_i
|
84
|
-
signature = generate_temporary_url_signature(options)
|
85
|
-
|
86
|
-
url = "http://#{S3::HOST}/#{bucket}/#{resource}"
|
87
|
-
url << "?AWSAccessKeyId=#{access_key}"
|
88
|
-
url << "&Expires=#{expires}"
|
89
|
-
url << "&Signature=#{signature}"
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
65
|
+
private
|
93
66
|
|
94
67
|
def self.canonicalized_signature(options)
|
95
68
|
headers = options[:headers] || {}
|
@@ -120,6 +93,7 @@ module Sndacs
|
|
120
93
|
digest = OpenSSL::Digest::Digest.new("sha1")
|
121
94
|
hmac = OpenSSL::HMAC.digest(digest, secret_access_key, string_to_sign)
|
122
95
|
base64 = Base64.encode64(hmac)
|
96
|
+
|
123
97
|
base64.chomp
|
124
98
|
end
|
125
99
|
|
@@ -209,7 +183,7 @@ module Sndacs
|
|
209
183
|
# requests that don't address a bucket, do nothing. For more
|
210
184
|
# information on virtual hosted-style requests, see Virtual
|
211
185
|
# Hosting of Buckets.
|
212
|
-
bucket_name = host.sub(/\.?storage
|
186
|
+
bucket_name = host.sub(/\.?storage[a-zA-Z0-9\-]*?\.grandcloud\.cn\Z/, "")
|
213
187
|
string << "/#{bucket_name}" unless bucket_name.empty?
|
214
188
|
|
215
189
|
# 3. Append the path part of the un-decoded HTTP Request-URI,
|
@@ -240,4 +214,5 @@ module Sndacs
|
|
240
214
|
string
|
241
215
|
end
|
242
216
|
end
|
217
|
+
|
243
218
|
end
|
data/lib/sndacs/version.rb
CHANGED
data/lib/sndacs.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
|
1
4
|
require "base64"
|
2
5
|
require "cgi"
|
3
6
|
require "digest/md5"
|
@@ -13,6 +16,7 @@ require "sndacs/objects_extension"
|
|
13
16
|
require "sndacs/buckets_extension"
|
14
17
|
require "sndacs/parser"
|
15
18
|
require "sndacs/bucket"
|
19
|
+
require "sndacs/config"
|
16
20
|
require "sndacs/connection"
|
17
21
|
require "sndacs/exceptions"
|
18
22
|
require "sndacs/object"
|
@@ -22,6 +26,28 @@ require "sndacs/signature"
|
|
22
26
|
require "sndacs/version"
|
23
27
|
|
24
28
|
module Sndacs
|
25
|
-
|
26
|
-
|
29
|
+
|
30
|
+
# Bucket default region
|
31
|
+
# NOTICE: DO NOT TOUCH THIS!!!
|
32
|
+
REGION_DEFAULT = 'huadong-1'
|
33
|
+
|
34
|
+
# Bucket region host template
|
35
|
+
# NOTICE: DO NOT TOUCH THIS!!!
|
36
|
+
REGION_HOST = 'storage-%s.grandcloud.cn'
|
37
|
+
|
38
|
+
# Object public access host template
|
39
|
+
# NOTICE: DO NOT TOUCH THIS!!!
|
40
|
+
REGION_CONTENT_HOST = 'storage-%s.sdcloud.cn'
|
41
|
+
|
42
|
+
# Default configurations, see Sndacs::Config for more info
|
43
|
+
#Config.access_key_id = ''
|
44
|
+
#Config.secret_access_key = ''
|
45
|
+
#Config.host = 'storage.grandcloud.cn'
|
46
|
+
#Config.content_host = 'storage.sdcloud.cn'
|
47
|
+
#Config.proxy = nil
|
48
|
+
#Config.timeout = 60
|
49
|
+
#Config.use_ssl = false
|
50
|
+
#Config.chunk_size = 1048576
|
51
|
+
#Config.debug = false
|
52
|
+
|
27
53
|
end
|
data/sndacs.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
|
-
# Load version requiring the canonical "
|
4
|
-
# is a different file and complaint about a double declaration of
|
3
|
+
# Load version requiring the canonical "sndacs/version", otherwise Ruby will think
|
4
|
+
# is a different file and complaint about a double declaration of Sndacs::VERSION.
|
5
5
|
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
6
6
|
require "sndacs/version"
|
7
7
|
|
@@ -12,16 +12,16 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.authors = ["LI Daobing"]
|
13
13
|
s.email = ["lidaobing@snda.com"]
|
14
14
|
s.homepage = "https://github.com/grandcloud/sndacs-ruby"
|
15
|
-
s.summary = "Library for accessing SNDA Cloud Storage
|
15
|
+
s.summary = "Library for accessing SNDA Cloud Storage buckets and objects"
|
16
16
|
s.description = "sndacs library provides access to SNDA Cloud Storage."
|
17
17
|
|
18
18
|
s.required_rubygems_version = ">= 1.3.6"
|
19
19
|
|
20
20
|
s.add_dependency "proxies", "~> 0.2.0"
|
21
|
-
s.add_development_dependency "test-unit", ">= 2.0"
|
22
|
-
s.add_development_dependency "mocha"
|
23
21
|
s.add_development_dependency "bundler", ">= 1.0.0"
|
24
22
|
s.add_development_dependency "rspec", "~> 2.0"
|
23
|
+
s.add_development_dependency "mocha"
|
24
|
+
#s.add_development_dependency "test-unit", ">= 2.0"
|
25
25
|
|
26
26
|
s.files = `git ls-files`.split("\n")
|
27
27
|
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|