cloudfiles 1.5.0 → 1.5.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -1
- data/cloudfiles.gemspec +1 -2
- data/lib/client.rb +6 -8
- data/lib/cloudfiles.rb +2 -5
- data/lib/cloudfiles/storage_object.rb +21 -15
- data/lib/cloudfiles/version.rb +1 -1
- data/test/cloudfiles_client_test.rb +6 -6
- data/test/cloudfiles_container_test.rb +1 -1
- metadata +6 -5
data/CHANGELOG
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
================================================================================
|
2
|
-
1.5.0 (2011/
|
2
|
+
1.5.0.1 (2011/12/05
|
3
|
+
================================================================================
|
4
|
+
o Fixed small bug with encoding or URI's
|
5
|
+
|
6
|
+
================================================================================
|
7
|
+
1.5.0 (2011/10/31)
|
3
8
|
================================================================================
|
4
9
|
o The underlying http wrapper now uses client.rb a simple abstraction to manage
|
5
10
|
each ReST call in its own function
|
data/cloudfiles.gemspec
CHANGED
@@ -3,7 +3,6 @@ require File.expand_path('../lib/cloudfiles/version', __FILE__)
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{cloudfiles}
|
5
5
|
s.version = CloudFiles::VERSION
|
6
|
-
|
7
6
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
7
|
s.authors = ["H. Wade Minter", "Rackspace Hosting"]
|
9
8
|
s.description = %q{A Ruby version of the Rackspace Cloud Files API.}
|
@@ -41,7 +40,7 @@ Gem::Specification.new do |s|
|
|
41
40
|
s.homepage = %q{http://www.rackspacecloud.com/cloud_hosting_products/files}
|
42
41
|
s.rdoc_options = ["--charset=UTF-8"]
|
43
42
|
s.require_paths = ["lib"]
|
44
|
-
s.rubygems_version = %q{1.5.0}
|
43
|
+
s.rubygems_version = %q{1.5.0.1}
|
45
44
|
s.summary = %q{A Ruby API into Rackspace Cloud Files}
|
46
45
|
s.test_files = [
|
47
46
|
"test/cf-testunit.rb",
|
data/lib/client.rb
CHANGED
@@ -34,16 +34,13 @@ end
|
|
34
34
|
class ChunkedConnectionWrapper
|
35
35
|
def initialize(data, chunk_size)
|
36
36
|
@size = chunk_size
|
37
|
-
|
38
|
-
@file = data
|
39
|
-
end
|
37
|
+
@file = data
|
40
38
|
end
|
41
39
|
|
42
40
|
def read(foo)
|
43
|
-
|
44
|
-
@file.read(@size)
|
45
|
-
end
|
41
|
+
@file.read(@size)
|
46
42
|
end
|
43
|
+
|
47
44
|
def eof!
|
48
45
|
@file.eof!
|
49
46
|
end
|
@@ -509,8 +506,9 @@ public
|
|
509
506
|
end
|
510
507
|
|
511
508
|
def self.put_object(url, token=nil, container=nil, name=nil, contents=nil,
|
512
|
-
content_length=nil, etag=nil, chunk_size=
|
509
|
+
content_length=nil, etag=nil, chunk_size=nil,
|
513
510
|
content_type=nil, headers={}, http_conn=nil, proxy=nil)
|
511
|
+
chunk_size ||= 65536
|
514
512
|
if not http_conn
|
515
513
|
http_conn = http_connection(url)
|
516
514
|
end
|
@@ -617,4 +615,4 @@ public
|
|
617
615
|
def delete_object(container, name, headers={})
|
618
616
|
_retry(nil, :delete_object, [container, name, headers])
|
619
617
|
end
|
620
|
-
end
|
618
|
+
end
|
data/lib/cloudfiles.rb
CHANGED
@@ -49,11 +49,8 @@ module CloudFiles
|
|
49
49
|
(str.respond_to?(:lines) ? str.lines : str).to_a.map { |x| x.chomp }
|
50
50
|
end
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
str.gsub(/([^a-zA-Z0-9_.-#{extra_exclude_chars}]+)/) do
|
55
|
-
'%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
|
56
|
-
end
|
52
|
+
def self.escape(str)
|
53
|
+
URI.encode(str)
|
57
54
|
end
|
58
55
|
end
|
59
56
|
|
@@ -17,7 +17,7 @@ module CloudFiles
|
|
17
17
|
@containername = container.name
|
18
18
|
@name = objectname
|
19
19
|
@make_path = make_path
|
20
|
-
@storagepath = "#{CloudFiles.escape @containername}/#{
|
20
|
+
@storagepath = "#{CloudFiles.escape @containername}/#{escaped_name}"
|
21
21
|
|
22
22
|
if force_exists
|
23
23
|
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless container.object_exists?(objectname)
|
@@ -35,7 +35,7 @@ module CloudFiles
|
|
35
35
|
def object_metadata
|
36
36
|
@object_metadata ||= (
|
37
37
|
begin
|
38
|
-
response = SwiftClient.head_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name,
|
38
|
+
response = SwiftClient.head_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name)
|
39
39
|
rescue ClientException => e
|
40
40
|
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless (e.status.to_s =~ /^20/)
|
41
41
|
end
|
@@ -57,6 +57,10 @@ module CloudFiles
|
|
57
57
|
)
|
58
58
|
end
|
59
59
|
|
60
|
+
def escaped_name
|
61
|
+
@escaped_name ||= escape_name @name
|
62
|
+
end
|
63
|
+
|
60
64
|
# Size of the object (in bytes)
|
61
65
|
def bytes
|
62
66
|
self.object_metadata[:bytes]
|
@@ -95,7 +99,7 @@ module CloudFiles
|
|
95
99
|
headers['Range'] = range
|
96
100
|
end
|
97
101
|
begin
|
98
|
-
response = SwiftClient.get_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name,
|
102
|
+
response = SwiftClient.get_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name)
|
99
103
|
response[1]
|
100
104
|
rescue ClientException => e
|
101
105
|
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless (e.status.to_s =~ /^20/)
|
@@ -122,7 +126,7 @@ module CloudFiles
|
|
122
126
|
headers['Range'] = range
|
123
127
|
end
|
124
128
|
begin
|
125
|
-
SwiftClient.get_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name,
|
129
|
+
SwiftClient.get_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name, nil, nil, &block)
|
126
130
|
end
|
127
131
|
end
|
128
132
|
|
@@ -146,7 +150,7 @@ module CloudFiles
|
|
146
150
|
headers = {}
|
147
151
|
metadatahash.each{ |key, value| headers['X-Object-Meta-' + key.to_s.capitalize] = value.to_s }
|
148
152
|
begin
|
149
|
-
SwiftClient.post_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name,
|
153
|
+
SwiftClient.post_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name, headers)
|
150
154
|
true
|
151
155
|
rescue ClientException => e
|
152
156
|
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" if (e.status.to_s == "404")
|
@@ -174,7 +178,7 @@ module CloudFiles
|
|
174
178
|
def set_manifest(manifest)
|
175
179
|
headers = {'X-Object-Manifest' => manifest}
|
176
180
|
begin
|
177
|
-
SwiftClient.post_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name,
|
181
|
+
SwiftClient.post_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name, headers)
|
178
182
|
true
|
179
183
|
rescue ClientException => e
|
180
184
|
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" if (response.code == "404")
|
@@ -217,7 +221,7 @@ module CloudFiles
|
|
217
221
|
# If we're taking data from standard input, send that IO object to cfreq
|
218
222
|
data = $stdin if (data.nil? && $stdin.tty? == false)
|
219
223
|
begin
|
220
|
-
response = SwiftClient.put_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name,
|
224
|
+
response = SwiftClient.put_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name, data, nil, nil, nil, nil, headers)
|
221
225
|
rescue ClientException => e
|
222
226
|
code = e.status.to_s
|
223
227
|
raise CloudFiles::Exception::InvalidResponse, "Invalid content-length header sent" if (code == "412")
|
@@ -250,7 +254,7 @@ module CloudFiles
|
|
250
254
|
headers = {}
|
251
255
|
headers = {"X-Purge-Email" => email} if email
|
252
256
|
begin
|
253
|
-
SwiftClient.delete_object(self.container.connection.cdnurl, self.container.connection.authtoken, self.container.escaped_name,
|
257
|
+
SwiftClient.delete_object(self.container.connection.cdnurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name, nil, headers)
|
254
258
|
true
|
255
259
|
rescue ClientException => e
|
256
260
|
raise CloudFiles::Exception::Connection, "Error Unable to Purge Object: #{@name}" unless (e.status.to_s =~ /^20.$/)
|
@@ -308,7 +312,6 @@ module CloudFiles
|
|
308
312
|
def save_to_filename(filename)
|
309
313
|
File.open(filename, 'wb+') do |f|
|
310
314
|
self.data_stream do |chunk|
|
311
|
-
puts chunk.length
|
312
315
|
f.write chunk
|
313
316
|
end
|
314
317
|
end
|
@@ -323,7 +326,7 @@ module CloudFiles
|
|
323
326
|
# private_object.public_url
|
324
327
|
# => nil
|
325
328
|
def public_url
|
326
|
-
self.container.public? ? self.container.cdn_url + "/#{
|
329
|
+
self.container.public? ? self.container.cdn_url + "/#{escaped_name}" : nil
|
327
330
|
end
|
328
331
|
|
329
332
|
# If the parent container is public (CDN-enabled), returns the SSL CDN URL to this object. Otherwise, return nil
|
@@ -334,7 +337,7 @@ module CloudFiles
|
|
334
337
|
# private_object.public_ssl_url
|
335
338
|
# => nil
|
336
339
|
def public_ssl_url
|
337
|
-
self.container.public? ? self.container.cdn_ssl_url + "/#{
|
340
|
+
self.container.public? ? self.container.cdn_ssl_url + "/#{escaped_name}" : nil
|
338
341
|
end
|
339
342
|
|
340
343
|
# If the parent container is public (CDN-enabled), returns the SSL CDN URL to this object. Otherwise, return nil
|
@@ -345,7 +348,7 @@ module CloudFiles
|
|
345
348
|
# private_object.public_streaming_url
|
346
349
|
# => nil
|
347
350
|
def public_streaming_url
|
348
|
-
self.container.public? ? self.container.cdn_streaming_url + "/#{
|
351
|
+
self.container.public? ? self.container.cdn_streaming_url + "/#{escaped_name}" : nil
|
349
352
|
end
|
350
353
|
|
351
354
|
# Copy this object to a new location (optionally in a new container)
|
@@ -371,9 +374,9 @@ module CloudFiles
|
|
371
374
|
new_name.sub!(/^\//,'')
|
372
375
|
headers = {'X-Copy-From' => "#{self.container.name}/#{self.name}", 'Content-Type' => self.content_type.sub(/;.+/, '')}.merge(new_headers)
|
373
376
|
# , 'Content-Type' => self.content_type
|
374
|
-
new_path = "#{CloudFiles.escape new_container}/#{
|
377
|
+
new_path = "#{CloudFiles.escape new_container}/#{escape_name new_name}"
|
375
378
|
begin
|
376
|
-
response = SwiftClient.put_object(self.container.connection.storageurl, self.container.connection.authtoken, (CloudFiles.escape new_container), (
|
379
|
+
response = SwiftClient.put_object(self.container.connection.storageurl, self.container.connection.authtoken, (CloudFiles.escape new_container), escape_name(new_name), nil, nil, nil, nil, nil, headers)
|
377
380
|
return CloudFiles::Container.new(self.container.connection, new_container).object(new_name)
|
378
381
|
rescue ClientException => e
|
379
382
|
code = e.status.to_s
|
@@ -392,11 +395,14 @@ module CloudFiles
|
|
392
395
|
return new_object
|
393
396
|
end
|
394
397
|
|
395
|
-
|
396
398
|
def to_s # :nodoc:
|
397
399
|
@name
|
398
400
|
end
|
399
401
|
|
402
|
+
def escape_name(name)
|
403
|
+
CloudFiles.escape name
|
404
|
+
end
|
405
|
+
|
400
406
|
private
|
401
407
|
|
402
408
|
def cdn_available?
|
data/lib/cloudfiles/version.rb
CHANGED
@@ -34,7 +34,9 @@ class SwiftClientTest < Test::Unit::TestCase
|
|
34
34
|
def test_query
|
35
35
|
query = Query.new("foo=bar&baz=quu")
|
36
36
|
query.add("chunky", "bacon")
|
37
|
-
|
37
|
+
assert_match /chunky=bacon/, query.to_s
|
38
|
+
assert_match /foo=bar/, query.to_s
|
39
|
+
assert_match /baz=quu/, query.to_s
|
38
40
|
assert query.has_key? "chunky"
|
39
41
|
query.delete("chunky")
|
40
42
|
assert_equal false, query.has_key?("chunky")
|
@@ -559,10 +561,8 @@ class SwiftClientTest < Test::Unit::TestCase
|
|
559
561
|
conn.stubs(:head).returns(response)
|
560
562
|
SwiftClient.expects(:http_connection).returns([@parsed, conn])
|
561
563
|
|
562
|
-
|
563
|
-
|
564
|
-
assert response.header, headers
|
565
|
-
end
|
564
|
+
headers = SwiftClient.head_object(@url, @token, 'test_container', 'test_object')
|
565
|
+
assert_equal response.header, headers
|
566
566
|
end
|
567
567
|
|
568
568
|
def test_head_object_fails
|
@@ -794,4 +794,4 @@ class SwiftClientTest < Test::Unit::TestCase
|
|
794
794
|
sc.delete_object('test_container', 'test_object')
|
795
795
|
end
|
796
796
|
end
|
797
|
-
end
|
797
|
+
end
|
@@ -95,7 +95,7 @@ class CloudfilesContainerTest < Test::Unit::TestCase
|
|
95
95
|
CloudFiles::Container.any_instance.stubs(:post_with_headers).returns(nil)
|
96
96
|
@container = CloudFiles::Container.new(connection, 'test_container')
|
97
97
|
assert_nothing_raised do
|
98
|
-
@container.make_public(123)
|
98
|
+
@container.make_public(:ttl => 123)
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudfiles
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 117
|
5
|
+
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 5
|
9
9
|
- 0
|
10
|
-
|
10
|
+
- 1
|
11
|
+
version: 1.5.0.1
|
11
12
|
platform: ruby
|
12
13
|
authors:
|
13
14
|
- H. Wade Minter
|
@@ -16,7 +17,7 @@ autorequire:
|
|
16
17
|
bindir: bin
|
17
18
|
cert_chain: []
|
18
19
|
|
19
|
-
date: 2011-
|
20
|
+
date: 2011-12-06 00:00:00 -06:00
|
20
21
|
default_executable:
|
21
22
|
dependencies:
|
22
23
|
- !ruby/object:Gem::Dependency
|
@@ -113,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
114
|
requirements: []
|
114
115
|
|
115
116
|
rubyforge_project:
|
116
|
-
rubygems_version: 1.
|
117
|
+
rubygems_version: 1.3.7
|
117
118
|
signing_key:
|
118
119
|
specification_version: 3
|
119
120
|
summary: A Ruby API into Rackspace Cloud Files
|