s3lib 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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