aws-sdk 1.0.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 (205) hide show
  1. data/.yardopts +6 -0
  2. data/LICENSE.txt +171 -0
  3. data/NOTICE.txt +2 -0
  4. data/README.rdoc +189 -0
  5. data/lib/aws-sdk.rb +14 -0
  6. data/lib/aws.rb +63 -0
  7. data/lib/aws/api_config.rb +45 -0
  8. data/lib/aws/api_config/.document +0 -0
  9. data/lib/aws/api_config/EC2-2011-02-28.yml +2314 -0
  10. data/lib/aws/api_config/SNS-2010-03-31.yml +171 -0
  11. data/lib/aws/api_config/SQS-2009-02-01.yml +161 -0
  12. data/lib/aws/api_config/SimpleDB-2009-04-15.yml +278 -0
  13. data/lib/aws/api_config/SimpleEmailService-2010-12-01.yml +147 -0
  14. data/lib/aws/api_config_transform.rb +32 -0
  15. data/lib/aws/async_handle.rb +90 -0
  16. data/lib/aws/authorize_v2.rb +37 -0
  17. data/lib/aws/authorize_v3.rb +37 -0
  18. data/lib/aws/base_client.rb +524 -0
  19. data/lib/aws/cacheable.rb +92 -0
  20. data/lib/aws/common.rb +228 -0
  21. data/lib/aws/configurable.rb +36 -0
  22. data/lib/aws/configuration.rb +272 -0
  23. data/lib/aws/configured_client_methods.rb +81 -0
  24. data/lib/aws/configured_grammars.rb +65 -0
  25. data/lib/aws/configured_option_grammars.rb +46 -0
  26. data/lib/aws/configured_xml_grammars.rb +47 -0
  27. data/lib/aws/default_signer.rb +38 -0
  28. data/lib/aws/ec2.rb +321 -0
  29. data/lib/aws/ec2/attachment.rb +149 -0
  30. data/lib/aws/ec2/attachment_collection.rb +57 -0
  31. data/lib/aws/ec2/availability_zone.rb +80 -0
  32. data/lib/aws/ec2/availability_zone_collection.rb +47 -0
  33. data/lib/aws/ec2/block_device_mappings.rb +53 -0
  34. data/lib/aws/ec2/client.rb +54 -0
  35. data/lib/aws/ec2/client/xml.rb +127 -0
  36. data/lib/aws/ec2/collection.rb +39 -0
  37. data/lib/aws/ec2/config_transform.rb +63 -0
  38. data/lib/aws/ec2/elastic_ip.rb +107 -0
  39. data/lib/aws/ec2/elastic_ip_collection.rb +85 -0
  40. data/lib/aws/ec2/errors.rb +29 -0
  41. data/lib/aws/ec2/filtered_collection.rb +65 -0
  42. data/lib/aws/ec2/has_permissions.rb +46 -0
  43. data/lib/aws/ec2/image.rb +245 -0
  44. data/lib/aws/ec2/image_collection.rb +235 -0
  45. data/lib/aws/ec2/instance.rb +515 -0
  46. data/lib/aws/ec2/instance_collection.rb +276 -0
  47. data/lib/aws/ec2/key_pair.rb +86 -0
  48. data/lib/aws/ec2/key_pair_collection.rb +102 -0
  49. data/lib/aws/ec2/permission_collection.rb +177 -0
  50. data/lib/aws/ec2/region.rb +81 -0
  51. data/lib/aws/ec2/region_collection.rb +55 -0
  52. data/lib/aws/ec2/request.rb +27 -0
  53. data/lib/aws/ec2/reserved_instances.rb +50 -0
  54. data/lib/aws/ec2/reserved_instances_collection.rb +44 -0
  55. data/lib/aws/ec2/reserved_instances_offering.rb +55 -0
  56. data/lib/aws/ec2/reserved_instances_offering_collection.rb +43 -0
  57. data/lib/aws/ec2/resource.rb +340 -0
  58. data/lib/aws/ec2/resource_tag_collection.rb +218 -0
  59. data/lib/aws/ec2/security_group.rb +246 -0
  60. data/lib/aws/ec2/security_group/ip_permission.rb +70 -0
  61. data/lib/aws/ec2/security_group/ip_permission_collection.rb +59 -0
  62. data/lib/aws/ec2/security_group_collection.rb +132 -0
  63. data/lib/aws/ec2/snapshot.rb +138 -0
  64. data/lib/aws/ec2/snapshot_collection.rb +90 -0
  65. data/lib/aws/ec2/tag.rb +88 -0
  66. data/lib/aws/ec2/tag_collection.rb +114 -0
  67. data/lib/aws/ec2/tagged_collection.rb +48 -0
  68. data/lib/aws/ec2/tagged_item.rb +87 -0
  69. data/lib/aws/ec2/volume.rb +190 -0
  70. data/lib/aws/ec2/volume_collection.rb +95 -0
  71. data/lib/aws/errors.rb +129 -0
  72. data/lib/aws/http/builtin_handler.rb +69 -0
  73. data/lib/aws/http/curb_handler.rb +123 -0
  74. data/lib/aws/http/handler.rb +77 -0
  75. data/lib/aws/http/httparty_handler.rb +61 -0
  76. data/lib/aws/http/request.rb +136 -0
  77. data/lib/aws/http/request_param.rb +63 -0
  78. data/lib/aws/http/response.rb +75 -0
  79. data/lib/aws/ignore_result_element.rb +38 -0
  80. data/lib/aws/indifferent_hash.rb +86 -0
  81. data/lib/aws/inflection.rb +46 -0
  82. data/lib/aws/lazy_error_classes.rb +64 -0
  83. data/lib/aws/meta_utils.rb +43 -0
  84. data/lib/aws/model.rb +57 -0
  85. data/lib/aws/naming.rb +32 -0
  86. data/lib/aws/option_grammar.rb +544 -0
  87. data/lib/aws/policy.rb +912 -0
  88. data/lib/aws/rails.rb +209 -0
  89. data/lib/aws/record.rb +79 -0
  90. data/lib/aws/record/attribute.rb +94 -0
  91. data/lib/aws/record/attribute_macros.rb +288 -0
  92. data/lib/aws/record/attributes/boolean.rb +49 -0
  93. data/lib/aws/record/attributes/datetime.rb +86 -0
  94. data/lib/aws/record/attributes/float.rb +48 -0
  95. data/lib/aws/record/attributes/integer.rb +68 -0
  96. data/lib/aws/record/attributes/sortable_float.rb +60 -0
  97. data/lib/aws/record/attributes/sortable_integer.rb +95 -0
  98. data/lib/aws/record/attributes/string.rb +69 -0
  99. data/lib/aws/record/base.rb +728 -0
  100. data/lib/aws/record/conversion.rb +38 -0
  101. data/lib/aws/record/dirty_tracking.rb +286 -0
  102. data/lib/aws/record/errors.rb +153 -0
  103. data/lib/aws/record/exceptions.rb +48 -0
  104. data/lib/aws/record/finder_methods.rb +262 -0
  105. data/lib/aws/record/naming.rb +31 -0
  106. data/lib/aws/record/scope.rb +157 -0
  107. data/lib/aws/record/validations.rb +653 -0
  108. data/lib/aws/record/validator.rb +237 -0
  109. data/lib/aws/record/validators/acceptance.rb +51 -0
  110. data/lib/aws/record/validators/block.rb +38 -0
  111. data/lib/aws/record/validators/confirmation.rb +43 -0
  112. data/lib/aws/record/validators/count.rb +108 -0
  113. data/lib/aws/record/validators/exclusion.rb +43 -0
  114. data/lib/aws/record/validators/format.rb +57 -0
  115. data/lib/aws/record/validators/inclusion.rb +56 -0
  116. data/lib/aws/record/validators/length.rb +107 -0
  117. data/lib/aws/record/validators/numericality.rb +138 -0
  118. data/lib/aws/record/validators/presence.rb +45 -0
  119. data/lib/aws/resource_cache.rb +39 -0
  120. data/lib/aws/response.rb +113 -0
  121. data/lib/aws/response_cache.rb +50 -0
  122. data/lib/aws/s3.rb +109 -0
  123. data/lib/aws/s3/access_control_list.rb +252 -0
  124. data/lib/aws/s3/acl_object.rb +266 -0
  125. data/lib/aws/s3/bucket.rb +320 -0
  126. data/lib/aws/s3/bucket_collection.rb +122 -0
  127. data/lib/aws/s3/bucket_version_collection.rb +85 -0
  128. data/lib/aws/s3/client.rb +999 -0
  129. data/lib/aws/s3/client/xml.rb +190 -0
  130. data/lib/aws/s3/data_options.rb +99 -0
  131. data/lib/aws/s3/errors.rb +43 -0
  132. data/lib/aws/s3/multipart_upload.rb +318 -0
  133. data/lib/aws/s3/multipart_upload_collection.rb +78 -0
  134. data/lib/aws/s3/object_collection.rb +159 -0
  135. data/lib/aws/s3/object_metadata.rb +67 -0
  136. data/lib/aws/s3/object_upload_collection.rb +83 -0
  137. data/lib/aws/s3/object_version.rb +141 -0
  138. data/lib/aws/s3/object_version_collection.rb +78 -0
  139. data/lib/aws/s3/paginated_collection.rb +94 -0
  140. data/lib/aws/s3/policy.rb +76 -0
  141. data/lib/aws/s3/prefix_and_delimiter_collection.rb +56 -0
  142. data/lib/aws/s3/prefixed_collection.rb +84 -0
  143. data/lib/aws/s3/presigned_post.rb +504 -0
  144. data/lib/aws/s3/request.rb +198 -0
  145. data/lib/aws/s3/s3_object.rb +794 -0
  146. data/lib/aws/s3/tree.rb +116 -0
  147. data/lib/aws/s3/tree/branch_node.rb +71 -0
  148. data/lib/aws/s3/tree/child_collection.rb +108 -0
  149. data/lib/aws/s3/tree/leaf_node.rb +99 -0
  150. data/lib/aws/s3/tree/node.rb +22 -0
  151. data/lib/aws/s3/tree/parent.rb +90 -0
  152. data/lib/aws/s3/uploaded_part.rb +82 -0
  153. data/lib/aws/s3/uploaded_part_collection.rb +86 -0
  154. data/lib/aws/service_interface.rb +60 -0
  155. data/lib/aws/simple_db.rb +202 -0
  156. data/lib/aws/simple_db/attribute.rb +159 -0
  157. data/lib/aws/simple_db/attribute_collection.rb +227 -0
  158. data/lib/aws/simple_db/client.rb +52 -0
  159. data/lib/aws/simple_db/client/options.rb +34 -0
  160. data/lib/aws/simple_db/client/xml.rb +68 -0
  161. data/lib/aws/simple_db/consistent_read_option.rb +42 -0
  162. data/lib/aws/simple_db/delete_attributes.rb +64 -0
  163. data/lib/aws/simple_db/domain.rb +118 -0
  164. data/lib/aws/simple_db/domain_collection.rb +116 -0
  165. data/lib/aws/simple_db/domain_metadata.rb +112 -0
  166. data/lib/aws/simple_db/errors.rb +46 -0
  167. data/lib/aws/simple_db/expect_condition_option.rb +45 -0
  168. data/lib/aws/simple_db/item.rb +84 -0
  169. data/lib/aws/simple_db/item_collection.rb +594 -0
  170. data/lib/aws/simple_db/item_data.rb +70 -0
  171. data/lib/aws/simple_db/put_attributes.rb +62 -0
  172. data/lib/aws/simple_db/request.rb +27 -0
  173. data/lib/aws/simple_email_service.rb +373 -0
  174. data/lib/aws/simple_email_service/client.rb +39 -0
  175. data/lib/aws/simple_email_service/client/options.rb +24 -0
  176. data/lib/aws/simple_email_service/client/xml.rb +38 -0
  177. data/lib/aws/simple_email_service/email_address_collection.rb +66 -0
  178. data/lib/aws/simple_email_service/errors.rb +29 -0
  179. data/lib/aws/simple_email_service/quotas.rb +64 -0
  180. data/lib/aws/simple_email_service/request.rb +27 -0
  181. data/lib/aws/sns.rb +69 -0
  182. data/lib/aws/sns/client.rb +37 -0
  183. data/lib/aws/sns/client/options.rb +24 -0
  184. data/lib/aws/sns/client/xml.rb +38 -0
  185. data/lib/aws/sns/errors.rb +29 -0
  186. data/lib/aws/sns/policy.rb +49 -0
  187. data/lib/aws/sns/request.rb +27 -0
  188. data/lib/aws/sns/subscription.rb +100 -0
  189. data/lib/aws/sns/subscription_collection.rb +84 -0
  190. data/lib/aws/sns/topic.rb +384 -0
  191. data/lib/aws/sns/topic_collection.rb +70 -0
  192. data/lib/aws/sns/topic_subscription_collection.rb +58 -0
  193. data/lib/aws/sqs.rb +70 -0
  194. data/lib/aws/sqs/client.rb +38 -0
  195. data/lib/aws/sqs/client/xml.rb +36 -0
  196. data/lib/aws/sqs/errors.rb +33 -0
  197. data/lib/aws/sqs/policy.rb +50 -0
  198. data/lib/aws/sqs/queue.rb +507 -0
  199. data/lib/aws/sqs/queue_collection.rb +105 -0
  200. data/lib/aws/sqs/received_message.rb +184 -0
  201. data/lib/aws/sqs/received_sns_message.rb +112 -0
  202. data/lib/aws/sqs/request.rb +44 -0
  203. data/lib/aws/xml_grammar.rb +923 -0
  204. data/rails/init.rb +15 -0
  205. metadata +298 -0
@@ -0,0 +1,190 @@
1
+ # Copyright 2011 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ require 'aws/xml_grammar'
15
+ require 'aws/base_client'
16
+
17
+ module AWS
18
+ class S3
19
+ class Client < BaseClient
20
+
21
+ # @private
22
+ module XML
23
+
24
+ Error = XmlGrammar.customize { }
25
+
26
+ module HasCommonPrefixes
27
+
28
+ def self.included(mod)
29
+ mod.module_eval do
30
+ element "CommonPrefixes" do
31
+ collect_values
32
+ format_value {|value| value.prefix }
33
+ end
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ ListBuckets = XmlGrammar.customize do
40
+ element "Buckets" do
41
+ element "Bucket" do
42
+ collect_values
43
+ end
44
+ format_value { |value| super(value.bucket) }
45
+ end
46
+ end
47
+
48
+ GetBucketAcl = GetObjectAcl = XmlGrammar.customize do
49
+ wrapper(:acl,
50
+ :for => ["Owner",
51
+ "AccessControlList"]) do
52
+ construct_value { AccessControlList.new }
53
+ end
54
+
55
+ element "Owner" do
56
+ construct_value { AccessControlList::Owner.new }
57
+ end
58
+
59
+ element "AccessControlList" do
60
+ element "Grant" do
61
+ collect_values
62
+ construct_value { AccessControlList::Grant.new }
63
+
64
+ element "Grantee" do
65
+ construct_value { AccessControlList::Grantee.new }
66
+ element "ID" do
67
+ rename :canonical_user_id
68
+ end
69
+ end
70
+
71
+ element "Permission" do
72
+ symbol_value
73
+ end
74
+ end
75
+
76
+ format_value { |value| super(value.grant) }
77
+ rename :grants
78
+
79
+ end
80
+ end
81
+
82
+ ListObjects = XmlGrammar.customize do
83
+
84
+ element("Name") { rename "bucket_name" }
85
+ element("MaxKeys") { integer_value }
86
+ element("IsTruncated") { rename "truncated"; boolean_value }
87
+ element("Delimiter") { force }
88
+
89
+ element("Contents") do
90
+ list
91
+ element("Owner") do
92
+ element("ID") { }
93
+ element("DisplayName") { }
94
+ end
95
+ element("Key") { }
96
+ element("Size") { }
97
+ element("StorageClass") { }
98
+ element("ETag") { rename "etag" }
99
+
100
+ # DateTime is more general, Time is much faster to construct
101
+ element("LastModified") { time_value }
102
+ end
103
+
104
+ include HasCommonPrefixes
105
+
106
+ end
107
+
108
+ GetBucketVersioning = XmlGrammar.customize do
109
+ element("Status") do
110
+ symbol_value
111
+ format_value {|value| super(value) || :unversioned }
112
+ force
113
+ end
114
+ end
115
+
116
+ ListObjectVersions = XmlGrammar.customize do
117
+
118
+ element("MaxKeys") { integer_value }
119
+ element("IsTruncated") { rename "Truncated"; boolean_value }
120
+ element("NextKeyMarker") { force }
121
+ element("NextVersionIdMarker") { force }
122
+
123
+ %w(DeleteMarker Version).each do |element_name|
124
+ element(element_name) do
125
+ collect_values
126
+ rename("versions")
127
+ element("IsLatest") { rename "latest"; boolean_value }
128
+ element("LastModified") { datetime_value }
129
+ element("ETag") { rename "etag" }
130
+ element("Size") { integer_value }
131
+ element("StorageClass") { symbol_value }
132
+ end
133
+ end
134
+
135
+ element "DeleteMarker" do
136
+ add_method(:delete_marker?) { true }
137
+ add_method(:version?) { false }
138
+ end
139
+
140
+ element "Version" do
141
+ add_method(:delete_marker?) { false }
142
+ add_method(:version?) { true }
143
+ end
144
+
145
+ include HasCommonPrefixes
146
+
147
+ end
148
+
149
+ # default behavior is good enough
150
+ InitiateMultipartUpload = XmlGrammar.customize do
151
+ element("UploadId") { force }
152
+ end
153
+
154
+ ListMultipartUploads = XmlGrammar.customize do
155
+ element("IsTruncated") { rename "Truncated"; boolean_value }
156
+ element("MaxUploads") { integer_value }
157
+ element("NextKeyMarker") { force }
158
+ element("NextUploadIdMarker") { force }
159
+ element("Upload") do
160
+ collect_values
161
+ rename :uploads
162
+ element("StorageClass") { symbol_value }
163
+ element("Initiated") { datetime_value }
164
+ end
165
+
166
+ include HasCommonPrefixes
167
+ end
168
+
169
+ # keep default behavior
170
+ CompleteMultipartUpload = XmlGrammar.customize
171
+
172
+ ListParts = XmlGrammar.customize do
173
+ element("StorageClass") { symbol_value }
174
+ element("IsTruncated") { rename "Truncated"; boolean_value }
175
+ element("MaxParts") { integer_value }
176
+ element("PartNumberMarker") { integer_value }
177
+ element("NextPartNumberMarker") { integer_value }
178
+ element("Part") do
179
+ collect_values
180
+ rename :parts
181
+ element("PartNumber") { integer_value }
182
+ element("LastModified") { datetime_value }
183
+ element("Size") { integer_value }
184
+ end
185
+ end
186
+
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,99 @@
1
+ # Copyright 2011 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ require 'pathname'
15
+
16
+ module AWS
17
+ class S3
18
+ module DataOptions
19
+
20
+ protected
21
+ def data_stream_from options, &block
22
+
23
+ validate_data!(options, block)
24
+
25
+ # block format
26
+ if block_given?
27
+ buffer = StringIO.new
28
+ yield(buffer)
29
+ buffer.rewind
30
+ return buffer
31
+ end
32
+
33
+ # string, pathname, file, io-like object, etc
34
+ data = options[:data]
35
+ file_opts = ["r"]
36
+ file_opts << { :encoding => "BINARY" } if Object.const_defined?(:Encoding)
37
+ case
38
+ when data.is_a?(String)
39
+ data.force_encoding("BINARY") if data.respond_to?(:force_encoding)
40
+ StringIO.new(data)
41
+ when data.is_a?(Pathname) then File.open(data.to_s, *file_opts)
42
+ when options[:file] then File.open(options[:file], *file_opts)
43
+ else data
44
+ end
45
+
46
+ end
47
+
48
+ protected
49
+ def content_length_from options
50
+ data = options[:data]
51
+ case
52
+ when options[:content_length] then options[:content_length]
53
+ when options[:file] then File.size(options[:file])
54
+ when data.is_a?(Pathname) then File.size(data.to_s)
55
+ when data.is_a?(File) then File.size(data.path)
56
+ when data.respond_to?(:bytesize) then data.bytesize
57
+ when data.respond_to?(:size) then data.size
58
+ when data.respond_to?(:length) then data.length
59
+ else raise ArgumentError, 'content_length was not provided ' +
60
+ 'and could not be determined'
61
+ end
62
+ end
63
+
64
+ protected
65
+ def validate_data! options, block
66
+
67
+ data = options[:data]
68
+ filename = options[:file]
69
+
70
+ raise ArgumentError, 'data passed multiple ways' if
71
+ [data, filename, block].compact.size > 1
72
+
73
+ # accepting block format
74
+ return if block and block.arity == 1
75
+
76
+ # accepting file path
77
+ return if filename.kind_of?(String)
78
+
79
+ # accepting strings
80
+ return if data.kind_of?(String)
81
+
82
+ # accepting pathname
83
+ return if data.kind_of?(Pathname)
84
+
85
+ # accepts io-like objects (responds to read and eof?)
86
+ if data.respond_to?(:read) and
87
+ data.method(:read).arity != 0 and
88
+ data.respond_to?(:eof?) then
89
+ return true
90
+ end
91
+
92
+ raise ArgumentError, 'data must be provided as a String, ' +
93
+ 'Pathname, file path, or an object that responds to #read and #eof?'
94
+
95
+ end
96
+
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,43 @@
1
+ # Copyright 2011 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ require 'aws/lazy_error_classes'
15
+ require 'aws/s3/client/xml'
16
+
17
+ module AWS
18
+ class S3
19
+
20
+ # This module contains exception classes for each of the error
21
+ # types that S3 can return. You can use these classes to rescue
22
+ # specific errors, for example:
23
+ #
24
+ # begin
25
+ # S3.new.buckets.mybucket.
26
+ # objects.myobj.write("HELLO")
27
+ # rescue S3::Errors::NoSuchBucket => e
28
+ # S3.new.buckets.create("mybucket")
29
+ # retry
30
+ # end
31
+ #
32
+ # All errors raised as a result of error responses from the
33
+ # service are instances of either {ClientError} or {ServerError}.
34
+ # @private
35
+ module Errors
36
+
37
+ BASE_ERROR_GRAMMAR = Client::XML::Error
38
+
39
+ include LazyErrorClasses
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,318 @@
1
+ # Copyright 2011 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ require 'aws/model'
15
+ require 'aws/s3/uploaded_part'
16
+ require 'aws/s3/uploaded_part_collection'
17
+ require 'thread'
18
+
19
+ module AWS
20
+ class S3
21
+
22
+ # Represents a multipart upload to an S3 object. See
23
+ # {S3Object#multipart_upload} for a convenient way to initiate a
24
+ # multipart upload.
25
+ class MultipartUpload
26
+
27
+ include Model
28
+
29
+ # @private
30
+ def initialize(object, id, options = {})
31
+ @id = id
32
+ @object = object
33
+
34
+ super
35
+
36
+ @completed_parts = {}
37
+ @increment_mutex = Mutex.new
38
+ @completed_mutex = Mutex.new
39
+ @last_part = 0
40
+ end
41
+
42
+ def bucket
43
+ object.bucket
44
+ end
45
+
46
+ def inspect
47
+ "<#{self.class}:#{object.bucket.name}/#{object.key}:#{id}>"
48
+ end
49
+ # @return [String] Returns the upload id.
50
+ attr_reader :id
51
+
52
+ alias_method :upload_id, :id
53
+
54
+ # @return [S3Object] Returns the object this upload is intended for.
55
+ attr_reader :object
56
+
57
+ # @return [Boolean] Returns true if both multipart uploads
58
+ # represent the same object and upload.
59
+ def ==(other)
60
+ other.kind_of?(MultipartUpload) and
61
+ other.object == object and
62
+ other.id == id
63
+ end
64
+
65
+ alias_method :eql?, :==
66
+
67
+ # @return [Boolean] True if the upload exists.
68
+ def exists?
69
+ client.list_parts(base_opts)
70
+ rescue Errors::NoSuchUpload => e
71
+ false
72
+ else
73
+ true
74
+ end
75
+
76
+ # @return The upload initiator. This object will have +:id+
77
+ # and +:display_name+ methods; if the initiator is an IAM
78
+ # user, the +:id+ method will return the ARN of the user, and
79
+ # if the initiator is an AWS account, this method will return
80
+ # the same data as {#owner}.
81
+ def initiator
82
+ client.list_parts(base_opts).initiator
83
+ end
84
+
85
+ # @return The upload owner. This object will have +:id+
86
+ # and +:display_name+ methods.
87
+ def owner
88
+ client.list_parts(base_opts).owner
89
+ end
90
+
91
+ # @return [Symbol] The class of storage used to store the
92
+ # uploaded object. Possible values:
93
+ #
94
+ # * +:standard+
95
+ # * +:reduced_redundancy?+
96
+ def storage_class
97
+ client.list_parts(base_opts).storage_class.downcase.to_sym
98
+ end
99
+
100
+ # @return [Boolean] True if the uploaded object will be stored
101
+ # with reduced redundancy.
102
+ def reduced_redundancy?
103
+ storage_class == :reduced_redundancy
104
+ end
105
+
106
+ # Aborts the upload. After a multipart upload is aborted, no
107
+ # additional parts can be uploaded using that upload ID. The
108
+ # storage consumed by any previously uploaded parts will be
109
+ # freed. However, if any part uploads are currently in
110
+ # progress, those part uploads might or might not succeed. As
111
+ # a result, it might be necessary to abort a given multipart
112
+ # upload multiple times in order to completely free all
113
+ # storage consumed by all parts.
114
+ # @return [nil]
115
+ def abort
116
+ client.abort_multipart_upload(base_opts)
117
+ @aborted = true
118
+ nil
119
+ end
120
+ alias_method :delete, :abort
121
+ alias_method :cancel, :abort
122
+
123
+ # @return [Boolean] True if the upload has been aborted.
124
+ # @see #abort
125
+ def aborted?
126
+ @aborted
127
+ end
128
+
129
+ # Uploads a part.
130
+ #
131
+ # @overload add_part(data, options = {})
132
+ #
133
+ # @param data The data to upload. Valid values include:
134
+ #
135
+ # * A string
136
+ #
137
+ # * A Pathname object
138
+ #
139
+ # * Any object responding to +read+ and +eof?+; the object
140
+ # must support the following access methods:
141
+ #
142
+ # read # all at once
143
+ # read(length) until eof? # in chunks
144
+ #
145
+ # If you specify data this way, you must also include
146
+ # the +:content_length+ option.
147
+ #
148
+ # @param [Hash] options Additional options for the upload.
149
+ #
150
+ # @option options [Integer] :content_length If provided,
151
+ # this option must match the total number of bytes written
152
+ # to S3 during the operation. This option is required if
153
+ # +:data+ is an IO-like object without a +size+ method.
154
+ #
155
+ # @overload add_part(options)
156
+ #
157
+ # @param [Hash] options Options for the upload. Either
158
+ # +:data+ or +:file+ is required.
159
+ #
160
+ # @option options :data The data to upload. Valid values
161
+ # include:
162
+ #
163
+ # * A string
164
+ #
165
+ # * A Pathname object
166
+ #
167
+ # * Any object responding to +read+ and +eof?+; the object
168
+ # must support the following access methods:
169
+ #
170
+ # read # all at once
171
+ # read(length) until eof? # in chunks
172
+ #
173
+ # If you specify data this way, you must also include
174
+ # the +:content_length+ option.
175
+ #
176
+ # @option options [String] :file Can be specified instead of
177
+ # +:data+; its value specifies the path of a file to
178
+ # upload.
179
+ #
180
+ # @option options [Integer] :content_length If provided,
181
+ # this option must match the total number of bytes written
182
+ # to S3 during the operation. This option is required if
183
+ # +:data+ is an IO-like object without a +size+ method.
184
+ def add_part(data_or_options, options = {})
185
+ if data_or_options.kind_of?(Hash)
186
+ part_options = base_opts.merge(data_or_options)
187
+ else
188
+ part_options = base_opts.merge(:data => data_or_options)
189
+ end
190
+ part_options.merge!(options)
191
+
192
+ unless part_options[:part_number]
193
+ @increment_mutex.synchronize do
194
+ part_options[:part_number] = (@last_part += 1)
195
+ end
196
+ end
197
+ part_number = part_options[:part_number]
198
+
199
+ resp = client.upload_part(part_options)
200
+ @completed_mutex.synchronize do
201
+ @completed_parts[part_number] = {
202
+ :part_number => part_number,
203
+ :etag => resp.etag
204
+ }
205
+ end
206
+ UploadedPart.new(self, part_number)
207
+ end
208
+
209
+ # Completes the upload by assembling previously uploaded
210
+ # parts.
211
+ #
212
+ # @return [S3Object, ObjectVersion] If the bucket has versioning
213
+ # enabled, returns the {ObjectVersion} representing the
214
+ # version that was uploaded. If versioning is disabled,
215
+ # returns the object.
216
+ def complete(*parts)
217
+ parts = parts.flatten
218
+ case parts.first
219
+ when :remote_parts
220
+ complete_opts = get_complete_opts
221
+ when :local_parts, nil
222
+ complete_opts = base_opts.merge(:parts => completed_parts)
223
+ else
224
+ part_numbers = parts.map do |part|
225
+ case part
226
+ when Integer
227
+ part
228
+ when UploadedPart
229
+ raise ArgumentError.new("cannot complete an upload with parts "+
230
+ "from a different upload") unless
231
+ part.upload == self
232
+
233
+ part.part_number
234
+ else
235
+ raise ArgumentError.new("expected number or UploadedPart")
236
+ end
237
+ end
238
+ complete_opts = get_complete_opts(part_numbers)
239
+ end
240
+
241
+ raise "no parts uploaded" if complete_opts[:parts].empty?
242
+
243
+ resp = client.complete_multipart_upload(complete_opts)
244
+ if resp.version_id
245
+ ObjectVersion.new(object, resp.version_id)
246
+ else
247
+ object
248
+ end
249
+ end
250
+
251
+ # Completes the upload or aborts it if no parts have been
252
+ # uploaded yet. Does nothing if the upload has already been
253
+ # aborted.
254
+ #
255
+ # @return [S3Object, ObjectVersion] If the bucket has versioning
256
+ # enabled, returns the {ObjectVersion} representing the
257
+ # version that was uploaded. If versioning is disabled,
258
+ # returns the object. If no upload was attempted (e.g. if it
259
+ # was aborted or if no parts were uploaded), returns +nil+.
260
+ def close
261
+ return if aborted?
262
+ if completed_parts.empty?
263
+ abort
264
+ else
265
+ complete
266
+ end
267
+ end
268
+
269
+ # @return [UploadedPartCollection] A collection representing
270
+ # the parts that have been uploaded to S3 for this upload.
271
+ def parts
272
+ UploadedPartCollection.new(self)
273
+ end
274
+
275
+ # @private
276
+ def completed_parts
277
+ @completed_parts.values.
278
+ sort { |a, b| a[:part_number] <=> b[:part_number] }
279
+ end
280
+
281
+ # @private
282
+ def inspect
283
+ "<#{self.class}:#{object.bucket.name}/#{object.key}:#{id}>"
284
+ end
285
+
286
+ # @private
287
+ private
288
+ def get_complete_opts(part_numbers = nil)
289
+ parts_resp = client.list_parts(base_opts)
290
+ complete_opts =
291
+ base_opts.merge(:parts =>
292
+ parts_resp.parts.map do |part|
293
+ { :part_number => part.part_number,
294
+ :etag => part.etag }
295
+ end)
296
+
297
+ complete_opts[:parts].reject! do |part|
298
+ !part_numbers.include?(part[:part_number])
299
+ end if part_numbers
300
+
301
+ complete_opts
302
+ end
303
+
304
+ # @private
305
+ private
306
+ def base_opts
307
+ opts = {
308
+ :bucket_name => object.bucket.name,
309
+ :key => object.key
310
+ }
311
+ opts[:upload_id] = upload_id if upload_id
312
+ opts
313
+ end
314
+
315
+ end
316
+
317
+ end
318
+ end