s3lib 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/Rakefile +24 -0
  2. data/VERSION.yml +5 -0
  3. data/bin/s3lib +15 -0
  4. data/bin/s3sh_as +15 -0
  5. data/github-test.rb +22 -0
  6. data/lib/acl.rb +134 -0
  7. data/lib/acl_access.rb +20 -0
  8. data/lib/acl_creating_a_grant_recipe.rb +95 -0
  9. data/lib/acl_reading_acl_recipe.rb +59 -0
  10. data/lib/acl_refreshing_cached_grants_recipe.rb +54 -0
  11. data/lib/bucket.rb +116 -0
  12. data/lib/bucket_before_refactoring.rb +120 -0
  13. data/lib/bucket_create.rb +39 -0
  14. data/lib/bucket_find.rb +41 -0
  15. data/lib/bucket_with_acl_mixin.rb +103 -0
  16. data/lib/error_handling.rb +12 -0
  17. data/lib/grant.rb +107 -0
  18. data/lib/grant_creating_a_grant_recipe.rb +103 -0
  19. data/lib/grant_reading_acl_recipe.rb +51 -0
  20. data/lib/object.rb +144 -0
  21. data/lib/object_from_bucket_test.rb +18 -0
  22. data/lib/object_take1.rb +150 -0
  23. data/lib/object_with_acl_mixin.rb +131 -0
  24. data/lib/put_with_curl_test.rb +39 -0
  25. data/lib/s3_authenticator.rb +155 -0
  26. data/lib/s3_authenticator_dev.rb +117 -0
  27. data/lib/s3_authenticator_dev_private.rb +40 -0
  28. data/lib/s3_errors.rb +58 -0
  29. data/lib/s3lib.rb +10 -0
  30. data/lib/s3lib_with_mixin.rb +11 -0
  31. data/lib/service.rb +24 -0
  32. data/lib/service_dev.rb +36 -0
  33. data/s3lib.gemspec +74 -0
  34. data/sample_usage.rb +45 -0
  35. data/test/acl_test.rb +89 -0
  36. data/test/amazon_headers_test.rb +87 -0
  37. data/test/canonical_resource_test.rb +53 -0
  38. data/test/canonical_string_tests.rb +73 -0
  39. data/test/first_test.rb +34 -0
  40. data/test/first_test_private.rb +55 -0
  41. data/test/full_test.rb +84 -0
  42. data/test/s3_authenticator_test.rb +291 -0
  43. metadata +109 -0
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'rake/testtask'
3
+
4
+ task :default => :test
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs << "test"
8
+ t.test_files = FileList['test/*_test.rb']
9
+ # t.verbose = true
10
+ end
11
+
12
+ begin
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gemspec|
15
+ gemspec.name = "s3lib"
16
+ gemspec.summary = "An Amazon S3 interface library used as an example in The S3 Cookbook (http://thes3cookbook.com)"
17
+ gemspec.email = 'scott@scottpatten.ca'
18
+ gemspec.homepage = 'http://thes3cookbook.com'
19
+ gemspec.description = "This library forms the basis for building a library to talk to Amazon S3 using Ruby. It is used as an example of how to build an Amazon S3 interface in The S3 Cookbook (http://thes3cookbook.com)"
20
+ gemspec.authors = ["Scott Patten"]
21
+ end
22
+ rescue LoadError
23
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
24
+ end
data/VERSION.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 0
3
+ :build:
4
+ :minor: 1
5
+ :patch: 0
data/bin/s3lib ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'yaml'
4
+
5
+ # Set the S3 keys to the right account if the account name was given in the command line
6
+ unless ARGV.empty?
7
+ s3_keys = YAML::load_file(File.join(ENV['HOME'], '.s3_keys.yml'))
8
+ if s3_keys.has_key?(ARGV[0])
9
+ keys = s3_keys[ARGV[0]]
10
+ ENV['AMAZON_ACCESS_KEY_ID'] = keys['amazon_access_key_id']
11
+ ENV['AMAZON_SECRET_ACCESS_KEY'] = keys['amazon_secret_access_key']
12
+ end
13
+ end
14
+
15
+ exec("irb -r s3lib")
data/bin/s3sh_as ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'yaml'
4
+
5
+ # Set the S3 keys to the right account if the account name was given in the command line
6
+ unless ARGV.empty?
7
+ s3_keys = YAML::load_file(File.join(ENV['HOME'], '.s3_keys.yml'))
8
+ if s3_keys.has_key?(ARGV[0])
9
+ keys = s3_keys[ARGV[0]]
10
+ ENV['AMAZON_ACCESS_KEY_ID'] = keys['amazon_access_key_id']
11
+ ENV['AMAZON_SECRET_ACCESS_KEY'] = keys['amazon_secret_access_key']
12
+ end
13
+ end
14
+
15
+ exec("s3sh")
data/github-test.rb ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ require 'yaml'
3
+
4
+ if ARGV.size < 1
5
+ puts "Usage: github-test.rb my-project.gemspec"
6
+ exit
7
+ end
8
+
9
+ require 'rubygems/specification'
10
+ data = File.read(ARGV[0])
11
+ spec = nil
12
+
13
+ if data !~ %r{!ruby/object:Gem::Specification}
14
+ Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
15
+ else
16
+ spec = YAML.load(data)
17
+ end
18
+
19
+ spec.validate
20
+
21
+ puts spec
22
+ puts "OK"
data/lib/acl.rb ADDED
@@ -0,0 +1,134 @@
1
+ module S3Lib
2
+
3
+ class Acl
4
+
5
+ attr_reader :xml, :parent, :url
6
+
7
+ def initialize(parent_or_url)
8
+ if parent_or_url.respond_to?(:url)
9
+ @parent = parent_or_url
10
+ @url = @parent.url.sub(/\/\Z/,'') + '?acl'
11
+ else
12
+ @url = parent_or_url.sub(/\/\Z/,'').sub(/\?acl/, '') + '?acl'
13
+ end
14
+ end
15
+
16
+ def grants(params = {})
17
+ refresh_grants if params[:refresh]
18
+ @grants || get_grants
19
+ end
20
+
21
+ def clear_grants
22
+ @grants = []
23
+ set_grants
24
+ end
25
+
26
+ # permission must be one of :read, :write, :read_acl, :write_acl or :full_control
27
+ # The grantee Hash should look like this:
28
+ # {:type => :canonical|:email|:all_s3|:public,
29
+ # :grantee => canonical_user_id | email_address}
30
+ #
31
+ # The :grantee element of the hash is only required (and meaningful)
32
+ # for :canonical and :email Grants
33
+ #
34
+ # Some examples:
35
+ # Add public read access to an object:
36
+ # add_grant(:read, :type => :public)
37
+ #
38
+ # Give write access to a user with email of 'test@example.com'
39
+ # add_grant(:write, :type => :email, :grantee => 'test@example.com')
40
+ #
41
+ # Give full control to user with canonical ID of 1234567890
42
+ # add_grant(:full_control, :type => :canonical, :grantee => 1234567890)
43
+ #
44
+ # Note that you still have to PUT your changes to the server.
45
+ # Do this using set_grants or use the bang version of add_grant
46
+ #
47
+ # add_grant(:read, :type => :public)
48
+ # set_grants()
49
+ #
50
+ # add_grant!(:read, :type => :public)
51
+ def add_grant(permission, grantee)
52
+ grants.push(S3Lib::Grant.new(permission, grantee))
53
+ end
54
+
55
+ # Add a grant and PUT it to the server right away
56
+ def add_grant!(permission, grantee)
57
+ add_grant(permission, grantee)
58
+ set_grants
59
+ end
60
+
61
+ def remove_grant(grant_num)
62
+ grants.delete_at(grant_num)
63
+ refresh_grants
64
+ end
65
+
66
+ def refresh_grants
67
+ get_grants
68
+ end
69
+
70
+ def set_grants
71
+ Acl.acl_request(:put, @url, :body => to_xml)
72
+ refresh_grants
73
+ end
74
+
75
+ def owner
76
+ get_grants unless @xml
77
+ @xml.elements['Owner'].elements['ID'].text
78
+ end
79
+
80
+ def to_xml
81
+ builder = Builder::XmlMarkup.new(:indent => 2)
82
+ xml = builder.AccessControlPolicy('xmlns' => 'http://s3.amazonaws.com/doc/2006-03-01/') do
83
+ builder.Owner do
84
+ builder.ID(owner)
85
+ end
86
+ builder.AccessControlList do
87
+ grants.each do |grant|
88
+ builder << grant.to_xml
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ def inspect
95
+ grants.collect do |grant|
96
+ grant.inspect
97
+ end.join("\n")
98
+ end
99
+
100
+ private
101
+
102
+ def get_grants
103
+ response = Acl.acl_request(:get, @url)
104
+ @xml = REXML::Document.new(response).root
105
+ @grants = REXML::XPath.match(@xml, '//Grant').collect do |grant|
106
+ grantee = grant.elements['Grantee']
107
+ permission = grant.elements['Permission'].text
108
+ S3Lib::Grant.new(permission, grantee)
109
+ end
110
+ end
111
+
112
+ def self.acl_request(verb, url, options = {})
113
+ begin
114
+ if verb == :put
115
+ options = {'content-type' => 'text/xml'}.merge(options) # Make sure content-type is set for :put
116
+ end
117
+ response = S3Lib.request(verb, url, options)
118
+ rescue S3Lib::S3ResponseError => error
119
+ puts "Error of type #{error.amazon_error_type}"
120
+ case error.amazon_error_type
121
+ when 'NoSuchBucket': raise S3Lib::BucketNotFoundError.new("The bucket '#{bucket}' does not exist.", error.io, error.s3requester)
122
+ when 'NotSignedUp': raise S3Lib::NotYourBucketError.new("The bucket '#{bucket}' is owned by somebody else", error.io, error.s3requester)
123
+ when 'AccessDenied': raise S3Lib::NotYourBucketError.new("The bucket '#{bucket}' is owned by someone else.", error.io, error.s3requester)
124
+ when 'MalformedACLError': raise S3Lib::MalformedACLError.new("Your ACL was malformed.", error.io, error.s3requester)
125
+ else # Re-raise the error if it's not one of the above
126
+ raise
127
+ end
128
+ end
129
+ response
130
+ end
131
+
132
+ end
133
+
134
+ end
data/lib/acl_access.rb ADDED
@@ -0,0 +1,20 @@
1
+ module S3Lib
2
+ module AclAccess
3
+
4
+ def refresh_acl
5
+ get_acl
6
+ end
7
+
8
+ def acl(params = {})
9
+ refresh_acl if params[:refresh]
10
+ @acl || get_acl
11
+ end
12
+
13
+ private
14
+
15
+ def get_acl
16
+ @acl = Acl.new(self)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,95 @@
1
+ module S3Lib
2
+
3
+ class Acl
4
+
5
+ attr_reader :xml, :url
6
+
7
+ def initialize(url)
8
+ @url = url.sub(/\/\Z/,'').sub(/\?acl/, '') + '?acl'
9
+ end
10
+
11
+ def grants(params = {})
12
+ refresh_grants if params[:refresh]
13
+ @grants || get_grants
14
+ end
15
+
16
+ # permission must be one of :read, :write, :read_acl, :write_acl or :full_control
17
+ # The grantee Hash should look like this:
18
+ # {:type => :canonical|:email|:all_s3|:public,
19
+ # :grantee => canonical_user_id | email_address}
20
+ #
21
+ # The :grantee element of the hash is only required (and meaningful)
22
+ # for :canonical and :email Grants
23
+ def add_grant(permission, grantee)
24
+ grants.push(S3Lib::Grant.new(permission, grantee))
25
+ end
26
+
27
+ # Add a grant and PUT it to the server right away
28
+ def add_grant!(permission, grantee)
29
+ add_grant(permission, grantee)
30
+ set_grants
31
+ end
32
+
33
+ def refresh_grants
34
+ get_grants
35
+ end
36
+
37
+ def set_grants
38
+ Acl.acl_request(:put, @url, :body => to_xml)
39
+ refresh_grants
40
+ end
41
+
42
+ def owner
43
+ get_grants unless @xml
44
+ @xml.elements['Owner'].elements['ID'].text
45
+ end
46
+
47
+ def to_xml
48
+ builder = Builder::XmlMarkup.new(:indent => 2)
49
+ xml = builder.AccessControlPolicy('xmlns' => 'http://s3.amazonaws.com/doc/2006-03-01/') do
50
+ builder.Owner do
51
+ builder.ID(owner)
52
+ end
53
+ builder.AccessControlList do
54
+ grants.each do |grant|
55
+ builder << grant.to_xml
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def get_grants
64
+ response = Acl.acl_request(:get, @url)
65
+ @xml = REXML::Document.new(response).root
66
+ @grants = REXML::XPath.match(@xml, '//Grant').collect do |grant|
67
+ grantee = grant.elements['Grantee']
68
+ permission = grant.elements['Permission'].text
69
+ S3Lib::Grant.new(permission, grantee)
70
+ end
71
+ end
72
+
73
+ def self.acl_request(verb, url, options = {})
74
+ begin
75
+ if verb == :put
76
+ options = {'content-type' => 'text/xml'}.merge(options) # Make sure content-type is set for :put
77
+ end
78
+ response = S3Lib.request(verb, url, options)
79
+ rescue S3Lib::S3ResponseError => error
80
+ puts "Error of type #{error.amazon_error_type}"
81
+ case error.amazon_error_type
82
+ when 'NoSuchBucket': raise S3Lib::BucketNotFoundError.new("The bucket '#{bucket}' does not exist.", error.io, error.s3requester)
83
+ when 'NotSignedUp': raise S3Lib::NotYourBucketError.new("The bucket '#{bucket}' is owned by somebody else", error.io, error.s3requester)
84
+ when 'AccessDenied': raise S3Lib::NotYourBucketError.new("The bucket '#{bucket}' is owned by someone else.", error.io, error.s3requester)
85
+ when 'MalformedACLError': raise S3Lib::MalformedACLError.new("Your ACL was malformed.", error.io, error.s3requester)
86
+ else # Re-raise the error if it's not one of the above
87
+ raise
88
+ end
89
+ end
90
+ response
91
+ end
92
+
93
+ end
94
+
95
+ end
@@ -0,0 +1,59 @@
1
+ module S3Lib
2
+ require 'rexml/document'
3
+ require File.join(File.dirname(__FILE__), 'grant_reading_acl_recipe.rb')
4
+ require File.join(File.dirname(__FILE__), 's3_authenticator.rb')
5
+
6
+ class Acl
7
+
8
+ attr_reader :xml, :url
9
+
10
+ def initialize(url)
11
+ @url = url.sub(/\/\Z/,'').sub(/\?acl/, '') + '?acl'
12
+ end
13
+
14
+ def grants(params = {})
15
+ refresh_grants if params[:refresh]
16
+ @grants || get_grants
17
+ end
18
+
19
+ def clear_grants
20
+ @grants = []
21
+ set_grants
22
+ end
23
+
24
+ def refresh_grants
25
+ get_grants
26
+ end
27
+
28
+ private
29
+
30
+ def get_grants
31
+ response = Acl.acl_request(:get, @url)
32
+ @xml = REXML::Document.new(response).root
33
+ @grants = REXML::XPath.match(@xml, '//Grant').collect do |grant|
34
+ grantee = grant.elements['Grantee']
35
+ permission = grant.elements['Permission'].text
36
+ S3Lib::Grant.new(permission, grantee)
37
+ end
38
+ end
39
+
40
+ def self.acl_request(verb, url, options = {})
41
+ begin
42
+ response = S3Lib.request(verb, url, options)
43
+ rescue S3Lib::S3ResponseError => error
44
+ puts "Error of type #{error.amazon_error_type}"
45
+ case error.amazon_error_type
46
+ when 'NoSuchBucket': raise S3Lib::BucketNotFoundError.new("The bucket '#{bucket}' does not exist.", error.io, error.s3requester)
47
+ when 'NotSignedUp': raise S3Lib::NotYourBucketError.new("The bucket '#{bucket}' is owned by somebody else", error.io, error.s3requester)
48
+ when 'AccessDenied': raise S3Lib::NotYourBucketError.new("The bucket '#{bucket}' is owned by someone else.", error.io, error.s3requester)
49
+ when 'MalformedACLError': raise S3Lib::MalformedACLError.new("Your ACL was malformed.", error.io, error.s3requester)
50
+ else # Re-raise the error if it's not one of the above
51
+ raise
52
+ end
53
+ end
54
+ response
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,54 @@
1
+ module S3Lib
2
+ require 'rexml/document'
3
+ require File.join(File.dirname(__FILE__), 'grant_reading_acl_recipe.rb')
4
+ require File.join(File.dirname(__FILE__), 's3_authenticator.rb')
5
+
6
+ class Acl
7
+
8
+ attr_reader :xml, :url
9
+
10
+ def initialize(url)
11
+ @url = url.sub(/\/\Z/,'').sub(/\?acl/, '') + '?acl'
12
+ end
13
+
14
+ def grants(params = {})
15
+ refresh_grants if params[:refresh]
16
+ @grants || get_grants
17
+ end
18
+
19
+ def refresh_grants
20
+ get_grants
21
+ end
22
+
23
+ private
24
+
25
+ def get_grants
26
+ response = Acl.acl_request(:get, @url)
27
+ @xml = REXML::Document.new(response).root
28
+ @grants = REXML::XPath.match(@xml, '//Grant').collect do |grant|
29
+ grantee = grant.elements['Grantee']
30
+ permission = grant.elements['Permission'].text
31
+ S3Lib::Grant.new(permission, grantee)
32
+ end
33
+ end
34
+
35
+ def self.acl_request(verb, url, options = {})
36
+ begin
37
+ response = S3Lib.request(verb, url, options)
38
+ rescue S3Lib::S3ResponseError => error
39
+ puts "Error of type #{error.amazon_error_type}"
40
+ case error.amazon_error_type
41
+ when 'NoSuchBucket': raise S3Lib::BucketNotFoundError.new("The bucket '#{bucket}' does not exist.", error.io, error.s3requester)
42
+ when 'NotSignedUp': raise S3Lib::NotYourBucketError.new("The bucket '#{bucket}' is owned by somebody else", error.io, error.s3requester)
43
+ when 'AccessDenied': raise S3Lib::NotYourBucketError.new("The bucket '#{bucket}' is owned by someone else.", error.io, error.s3requester)
44
+ when 'MalformedACLError': raise S3Lib::MalformedACLError.new("Your ACL was malformed.", error.io, error.s3requester)
45
+ else # Re-raise the error if it's not one of the above
46
+ raise
47
+ end
48
+ end
49
+ response
50
+ end
51
+
52
+ end
53
+
54
+ end
data/lib/bucket.rb ADDED
@@ -0,0 +1,116 @@
1
+ # bucket.rb
2
+ module S3Lib
3
+
4
+ class Bucket
5
+
6
+ attr_reader :name, :xml, :prefix, :marker, :max_keys
7
+
8
+ def self.create(name, params = {})
9
+ params['x-amz-acl'] = params.delete(:access) if params[:access] # translate from :access to 'x-amz-acl'
10
+ response = self.bucket_request(:put, name, params)
11
+ response.status[0] == "200" ? true : false
12
+ end
13
+
14
+ # passing :force => true will cause the bucket to be deleted even if it is not empty.
15
+ def self.delete(name, params = {})
16
+ if params.delete(:force)
17
+ self.delete_all(name, params)
18
+ end
19
+ response = self.bucket_request(:delete, name, params)
20
+ end
21
+
22
+ def delete(params = {})
23
+ self.class.delete(@name, @params.merge(params))
24
+ end
25
+
26
+ def self.delete_all(name, params = {})
27
+ bucket = Bucket.find(name, params)
28
+ bucket.delete_all
29
+ end
30
+
31
+ def delete_all
32
+ objects.each do |object|
33
+ object.delete
34
+ end
35
+ end
36
+
37
+ def self.find(name, params = {})
38
+ response = self.bucket_request(:get, name, params)
39
+ doc = REXML::Document.new(response).root
40
+ Bucket.new(doc, params)
41
+ end
42
+
43
+ def initialize(doc, params = {})
44
+ @xml = doc
45
+ @params = params
46
+ # The XML has to have a name, but Service::buckets doesn't return
47
+ # MaxKeys, Prefix or Marker elements
48
+ @name = @xml.elements['Name'].text
49
+ @max_keys = @xml.elements['MaxKeys'].text.to_i if @xml.elements['MaxKeys']
50
+ @prefix = @xml.elements['Prefix'].text if @xml.elements['Prefix']
51
+ @marker = @xml.elements['Marker'].text if @xml.elements['Marker']
52
+ end
53
+
54
+ def is_truncated?
55
+ @xml.elements['IsTruncated'].text == 'true'
56
+ end
57
+
58
+ def objects(params = {})
59
+ refresh if params[:refresh]
60
+ @objects || get_objects
61
+ end
62
+
63
+ def refresh
64
+ refreshed_bucket = Bucket.find(@name, @params)
65
+ @xml = refreshed_bucket.xml
66
+ @objects = nil
67
+ end
68
+
69
+ def refresh_acl
70
+ get_acl
71
+ end
72
+
73
+ def url
74
+ @name
75
+ end
76
+
77
+ # access an object in the bucket by key name
78
+ def [](key)
79
+ objects.detect{|object| object.key == key}
80
+ end
81
+
82
+ def acl(params = {})
83
+ refresh_acl if params[:refresh]
84
+ @acl || get_acl
85
+ end
86
+
87
+ private
88
+
89
+ def self.bucket_request(verb, name, params = {})
90
+ begin
91
+ response = S3Lib.request(verb, name, params)
92
+ rescue S3Lib::S3ResponseError => error
93
+ case error.amazon_error_type
94
+ when "NoSuchBucket": raise S3Lib::BucketNotFoundError.new("The bucket '#{name}' does not exist.", error.io, error.s3requester)
95
+ when "NotSignedUp": raise S3Lib::NotYourBucketError.new("The bucket '#{name}' is owned by someone else.", error.io, error.s3requester)
96
+ when "BucketNotEmpty": raise S3Lib::BucketNotEmptyError.new("The bucket '#{name}' is not empty, so you can't delete it.\nTry using Bucket.delete_all('#{name}') first, or Bucket.delete('#{name}', :force => true).", error.io, error.s3requester)
97
+ else # Re-raise the error if it's not one of the above
98
+ raise
99
+ end
100
+ end
101
+ end
102
+
103
+ def get_objects
104
+ @objects = REXML::XPath.match(@xml, '//Contents').collect do |object|
105
+ key = object.elements['Key'].text
106
+ S3Lib::S3Object.new(self, key, :lazy_load => true)
107
+ end
108
+ end
109
+
110
+ def get_acl
111
+ @acl = Acl.new(self)
112
+ end
113
+
114
+ end
115
+
116
+ end
@@ -0,0 +1,120 @@
1
+ # bucket.rb
2
+ require File.join(File.dirname(__FILE__), 's3_authenticator')
3
+ require 'rexml/document'
4
+
5
+ module S3Lib
6
+
7
+ class NotYourBucketError < S3Lib::S3ResponseError
8
+ end
9
+
10
+ class BucketNotFoundError < S3Lib::S3ResponseError
11
+ end
12
+
13
+ class BucketNotEmptyError < S3Lib::S3ResponseError
14
+ end
15
+
16
+ class Bucket
17
+
18
+ attr_reader :name, :xml, :prefix, :marker, :max_keys
19
+
20
+ def self.create(name, params = {})
21
+ params['x-amz-acl'] = params.delete(:access) if params[:access] # translate from :access to 'x-amz-acl'
22
+ begin
23
+ response = S3Lib.request(:put, name, params)
24
+ rescue OpenURI::HTTPError => error
25
+ if error.amazon_error_type == "BucketAlreadyExists"
26
+ S3Lib::NotYourBucketError.new("The bucket '#{name}' is already owned by somebody else", error.io, error.s3requester)
27
+ else
28
+ raise # re-raise the exception if it's not a BucketAlreadyExists error
29
+ end
30
+ end
31
+ response.status[0] == "200" ? true : false
32
+ end
33
+
34
+ # passing :force => true will cause the bucket to be deleted even if it is not empty.
35
+ def self.delete(name, params = {})
36
+ if params.delete(:force)
37
+ self.delete_all(name, params)
38
+ end
39
+ begin
40
+ response = S3Lib.request(:delete, name, params)
41
+ rescue S3Lib::S3ResponseError => error
42
+ case error.amazon_error_type
43
+ when "NoSuchBucket": raise S3Lib::BucketNotFoundError.new("The bucket '#{name}' does not exist.", error.io, error.s3requester)
44
+ when "NotSignedUp": raise S3Lib::NotYourBucketError.new("The bucket '#{name}' is not owned by you.", error.io, error.s3requester)
45
+ when "BucketNotEmpty": raise S3Lib::BucketNotEmptyError.new("The bucket '#{name}' is not empty, so you can't delete it.\nTry using Bucket.delete_all('#{name}') first, or Bucket.delete('#{name}', :force => true).", error.io, error.s3requester)
46
+ else # Re-raise the error if it's not one of the above
47
+ raise
48
+ end
49
+ end
50
+ end
51
+
52
+ def delete(params = {})
53
+ self.class.delete(@name, @params.merge(params))
54
+ end
55
+
56
+ def self.delete_all(name, params = {})
57
+ bucket = Bucket.find(name, params)
58
+ bucket.delete_all
59
+ end
60
+
61
+ def delete_all
62
+ objects.each do |object|
63
+ object.delete
64
+ end
65
+ end
66
+
67
+ # Errors for find
68
+ # Trying to find a bucket that doesn't exist will raise a NoSuchBucket error
69
+ # Trying to find a bucket that you don't have access to will raise a NotSignedUp error
70
+ def self.find(name, params = {})
71
+ begin
72
+ response = S3Lib.request(:get, name)
73
+ rescue S3Lib::S3ResponseError => error
74
+ case error.amazon_error_type
75
+ when "NoSuchBucket": raise S3Lib::BucketNotFoundError.new("The bucket '#{name}' does not exist.", error.io, error.s3requester)
76
+ when "NotSignedUp": raise S3Lib::NotYourBucketError.new("The bucket '#{name}' is not owned by you", error.io, error.s3requester)
77
+ else # Re-raise the error if it's not one of the above
78
+ raise
79
+ end
80
+ end
81
+ doc = REXML::Document.new(response)
82
+ Bucket.new(doc, params)
83
+ end
84
+
85
+ def initialize(doc, params = {})
86
+ @xml = doc.root
87
+ @params = params
88
+ @name = @xml.elements['Name'].text
89
+ @max_keys = @xml.elements['MaxKeys'].text.to_i
90
+ @prefix = @xml.elements['Prefix'].text
91
+ @marker = @xml.elements['Marker'].text
92
+ end
93
+
94
+ def is_truncated?
95
+ @xml.elements['IsTruncated'].text == 'true'
96
+ end
97
+
98
+ def objects(params = {})
99
+ refresh if params[:refresh]
100
+ @objects || get_objects
101
+ end
102
+
103
+ def refresh
104
+ refreshed_bucket = Bucket.find(@name, @params)
105
+ @xml = refreshed_bucket.xml
106
+ @objects = nil
107
+ end
108
+
109
+ private
110
+
111
+ def get_objects
112
+ @objects = REXML::XPath.match(@xml, '//Contents').collect do |object|
113
+ key = object.elements['Key'].text
114
+ S3Lib::S3Object.new(self, key, :lazy_load => true)
115
+ end
116
+ end
117
+
118
+ end
119
+
120
+ end