mss-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 (131) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +9 -0
  3. data/LICENSE.txt +0 -0
  4. data/README.md +192 -0
  5. data/bin/mss-rb +178 -0
  6. data/ca-bundle.crt +3554 -0
  7. data/lib/mss/core/async_handle.rb +89 -0
  8. data/lib/mss/core/cacheable.rb +76 -0
  9. data/lib/mss/core/client.rb +786 -0
  10. data/lib/mss/core/collection/simple.rb +81 -0
  11. data/lib/mss/core/collection/with_limit_and_next_token.rb +70 -0
  12. data/lib/mss/core/collection/with_next_token.rb +96 -0
  13. data/lib/mss/core/collection.rb +262 -0
  14. data/lib/mss/core/configuration.rb +527 -0
  15. data/lib/mss/core/credential_providers.rb +653 -0
  16. data/lib/mss/core/data.rb +251 -0
  17. data/lib/mss/core/deprecations.rb +83 -0
  18. data/lib/mss/core/endpoints.rb +36 -0
  19. data/lib/mss/core/http/connection_pool.rb +374 -0
  20. data/lib/mss/core/http/curb_handler.rb +150 -0
  21. data/lib/mss/core/http/handler.rb +88 -0
  22. data/lib/mss/core/http/net_http_handler.rb +144 -0
  23. data/lib/mss/core/http/patch.rb +98 -0
  24. data/lib/mss/core/http/request.rb +258 -0
  25. data/lib/mss/core/http/response.rb +80 -0
  26. data/lib/mss/core/indifferent_hash.rb +87 -0
  27. data/lib/mss/core/inflection.rb +55 -0
  28. data/lib/mss/core/ini_parser.rb +41 -0
  29. data/lib/mss/core/json_client.rb +46 -0
  30. data/lib/mss/core/json_parser.rb +75 -0
  31. data/lib/mss/core/json_request_builder.rb +34 -0
  32. data/lib/mss/core/json_response_parser.rb +78 -0
  33. data/lib/mss/core/lazy_error_classes.rb +107 -0
  34. data/lib/mss/core/log_formatter.rb +426 -0
  35. data/lib/mss/core/managed_file.rb +31 -0
  36. data/lib/mss/core/meta_utils.rb +44 -0
  37. data/lib/mss/core/model.rb +61 -0
  38. data/lib/mss/core/naming.rb +29 -0
  39. data/lib/mss/core/option_grammar.rb +737 -0
  40. data/lib/mss/core/options/json_serializer.rb +81 -0
  41. data/lib/mss/core/options/validator.rb +154 -0
  42. data/lib/mss/core/options/xml_serializer.rb +117 -0
  43. data/lib/mss/core/page_result.rb +74 -0
  44. data/lib/mss/core/policy.rb +938 -0
  45. data/lib/mss/core/query_client.rb +40 -0
  46. data/lib/mss/core/query_error_parser.rb +23 -0
  47. data/lib/mss/core/query_request_builder.rb +46 -0
  48. data/lib/mss/core/query_response_parser.rb +34 -0
  49. data/lib/mss/core/region.rb +84 -0
  50. data/lib/mss/core/region_collection.rb +79 -0
  51. data/lib/mss/core/resource.rb +412 -0
  52. data/lib/mss/core/resource_cache.rb +39 -0
  53. data/lib/mss/core/response.rb +214 -0
  54. data/lib/mss/core/response_cache.rb +49 -0
  55. data/lib/mss/core/rest_error_parser.rb +23 -0
  56. data/lib/mss/core/rest_json_client.rb +39 -0
  57. data/lib/mss/core/rest_request_builder.rb +153 -0
  58. data/lib/mss/core/rest_response_parser.rb +65 -0
  59. data/lib/mss/core/rest_xml_client.rb +46 -0
  60. data/lib/mss/core/service_interface.rb +82 -0
  61. data/lib/mss/core/signers/base.rb +45 -0
  62. data/lib/mss/core/signers/cloud_front.rb +55 -0
  63. data/lib/mss/core/signers/s3.rb +158 -0
  64. data/lib/mss/core/signers/version_2.rb +71 -0
  65. data/lib/mss/core/signers/version_3.rb +85 -0
  66. data/lib/mss/core/signers/version_3_https.rb +60 -0
  67. data/lib/mss/core/signers/version_4/chunk_signed_stream.rb +190 -0
  68. data/lib/mss/core/signers/version_4.rb +227 -0
  69. data/lib/mss/core/uri_escape.rb +43 -0
  70. data/lib/mss/core/xml/frame.rb +245 -0
  71. data/lib/mss/core/xml/frame_stack.rb +84 -0
  72. data/lib/mss/core/xml/grammar.rb +306 -0
  73. data/lib/mss/core/xml/parser.rb +69 -0
  74. data/lib/mss/core/xml/root_frame.rb +64 -0
  75. data/lib/mss/core/xml/sax_handlers/libxml.rb +46 -0
  76. data/lib/mss/core/xml/sax_handlers/nokogiri.rb +55 -0
  77. data/lib/mss/core/xml/sax_handlers/ox.rb +40 -0
  78. data/lib/mss/core/xml/sax_handlers/rexml.rb +46 -0
  79. data/lib/mss/core/xml/stub.rb +122 -0
  80. data/lib/mss/core.rb +602 -0
  81. data/lib/mss/errors.rb +161 -0
  82. data/lib/mss/rails.rb +194 -0
  83. data/lib/mss/s3/access_control_list.rb +262 -0
  84. data/lib/mss/s3/acl_object.rb +263 -0
  85. data/lib/mss/s3/acl_options.rb +200 -0
  86. data/lib/mss/s3/bucket.rb +757 -0
  87. data/lib/mss/s3/bucket_collection.rb +161 -0
  88. data/lib/mss/s3/bucket_lifecycle_configuration.rb +472 -0
  89. data/lib/mss/s3/bucket_region_cache.rb +51 -0
  90. data/lib/mss/s3/bucket_tag_collection.rb +110 -0
  91. data/lib/mss/s3/bucket_version_collection.rb +78 -0
  92. data/lib/mss/s3/cipher_io.rb +119 -0
  93. data/lib/mss/s3/client/xml.rb +265 -0
  94. data/lib/mss/s3/client.rb +2076 -0
  95. data/lib/mss/s3/config.rb +60 -0
  96. data/lib/mss/s3/cors_rule.rb +107 -0
  97. data/lib/mss/s3/cors_rule_collection.rb +193 -0
  98. data/lib/mss/s3/data_options.rb +190 -0
  99. data/lib/mss/s3/encryption_utils.rb +145 -0
  100. data/lib/mss/s3/errors.rb +93 -0
  101. data/lib/mss/s3/multipart_upload.rb +353 -0
  102. data/lib/mss/s3/multipart_upload_collection.rb +75 -0
  103. data/lib/mss/s3/object_collection.rb +355 -0
  104. data/lib/mss/s3/object_metadata.rb +102 -0
  105. data/lib/mss/s3/object_upload_collection.rb +76 -0
  106. data/lib/mss/s3/object_version.rb +153 -0
  107. data/lib/mss/s3/object_version_collection.rb +88 -0
  108. data/lib/mss/s3/paginated_collection.rb +74 -0
  109. data/lib/mss/s3/policy.rb +73 -0
  110. data/lib/mss/s3/prefix_and_delimiter_collection.rb +46 -0
  111. data/lib/mss/s3/prefixed_collection.rb +84 -0
  112. data/lib/mss/s3/presign_v4.rb +135 -0
  113. data/lib/mss/s3/presigned_post.rb +574 -0
  114. data/lib/mss/s3/region_detection.rb +75 -0
  115. data/lib/mss/s3/request.rb +61 -0
  116. data/lib/mss/s3/s3_object.rb +1795 -0
  117. data/lib/mss/s3/tree/branch_node.rb +67 -0
  118. data/lib/mss/s3/tree/child_collection.rb +103 -0
  119. data/lib/mss/s3/tree/leaf_node.rb +93 -0
  120. data/lib/mss/s3/tree/node.rb +21 -0
  121. data/lib/mss/s3/tree/parent.rb +86 -0
  122. data/lib/mss/s3/tree.rb +115 -0
  123. data/lib/mss/s3/uploaded_part.rb +81 -0
  124. data/lib/mss/s3/uploaded_part_collection.rb +83 -0
  125. data/lib/mss/s3/website_configuration.rb +101 -0
  126. data/lib/mss/s3.rb +161 -0
  127. data/lib/mss/version.rb +16 -0
  128. data/lib/mss-sdk.rb +2 -0
  129. data/lib/mss.rb +14 -0
  130. data/rails/init.rb +14 -0
  131. metadata +201 -0
@@ -0,0 +1,355 @@
1
+ # Copyright 2011-2013 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
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ class S3
15
+
16
+ # Represents a collection of S3 objects.
17
+ #
18
+ # ## Getting an S3Object by Key
19
+ #
20
+ # If you know the key of the object you want, you can reference it this way:
21
+ #
22
+ # # this will not make any requests against S3
23
+ # object = bucket.objects['foo.jpg']
24
+ # object.key #=> 'foo.jpg'
25
+ #
26
+ # ## Finding objects with a Prefix
27
+ #
28
+ # Given a bucket with the following keys:
29
+ #
30
+ # photos/sunset.jpg
31
+ # photos/sunrise.jpg
32
+ # photos/winter.jpg
33
+ # videos/comedy.mpg
34
+ # videos/dancing.mpg
35
+ #
36
+ # You can list objects that share a prefix:
37
+ #
38
+ # bucket.objects.with_prefix('videos').collect(&:key)
39
+ # #=> ['videos/comedy.mpg', 'videos/dancing.mpg']
40
+ #
41
+ # ## Exploring Objects with a Tree Interface
42
+ #
43
+ # Given a bucket with the following keys:
44
+ #
45
+ # README.txt
46
+ # videos/wedding.mpg
47
+ # videos/family_reunion.mpg
48
+ # photos/2010/house.jpg
49
+ # photos/2011/fall/leaves.jpg
50
+ # photos/2011/summer/vacation.jpg
51
+ # photos/2011/summer/family.jpg
52
+ #
53
+ # tree = bucket.objects.with_prefix('photos').as_tree
54
+ #
55
+ # directories = tree.children.select(&:branch?).collect(&:prefix)
56
+ # #=> ['photos/2010', 'photos/2011']
57
+ #
58
+ class ObjectCollection
59
+
60
+ include Core::Model
61
+ include Enumerable
62
+ include PrefixAndDelimiterCollection
63
+
64
+ # @param [Bucket] bucket The S3 bucket this object collection belongs to.
65
+ # @param [Hash] options
66
+ def initialize(bucket, options = {})
67
+ @bucket = bucket
68
+ super
69
+ end
70
+
71
+ # @return [Bucket] The bucket this collection belongs to.
72
+ attr_reader :bucket
73
+
74
+ # Writes a new object to S3.
75
+ #
76
+ # The first param is the key you want to write this object to.
77
+ # All other params/options are documented in {S3Object#write}.
78
+ #
79
+ # @see S3Object#write
80
+ #
81
+ # @param [String] key Where in S3 to write the object.
82
+ # @return (see S3Object#write)
83
+ def create key, *args, &block
84
+ self[key].write(*args, &block)
85
+ end
86
+
87
+ # Returns an S3Object given its name. For example:
88
+ #
89
+ # @example
90
+ #
91
+ # object = bucket.objects['file.txt']
92
+ # object.class #=> S3Object
93
+ #
94
+ # @param [String] key The object key.
95
+ # @return [S3Object]
96
+ def [] key
97
+ S3Object.new(bucket, key.to_s)
98
+ end
99
+
100
+ # (see PrefixedCollection#with_prefix)
101
+ def with_prefix prefix, mode = :replace
102
+ super(prefix, mode)
103
+ end
104
+
105
+ # Deletes the objects provided in as few requests as possible.
106
+ #
107
+ # # delete 2 objects (by key) in a single request
108
+ # bucket.objects.delete('abc', 'xyz')
109
+ #
110
+ # You can delete objects also by passing their S3Object representation:
111
+ #
112
+ # to_delete = []
113
+ # to_delete << buckets.objects['foo']
114
+ # to_delete << buckets.objects['bar']
115
+ #
116
+ # bucket.objects.delete(to_delete)
117
+ #
118
+ # @overload delete(objects)
119
+ # @param [Mixed] objects One or more objects to delete. Each object
120
+ # can be one of the following:
121
+ #
122
+ # * An object key (string)
123
+ # * A hash with :key and :version_id (for versioned objects)
124
+ # * An {S3Object} instance
125
+ # * An {ObjectVersion} instance
126
+ #
127
+ # @overload delete(objects, options)
128
+ # Deletes multiple objects, with additional options. The array can
129
+ # contain any of the types of objects the first method invocation style
130
+ # accepts.
131
+ # @param [Array] objects One or more objects to delete.
132
+ # @param [Hash] options Optional headers to pass on.
133
+ #
134
+ # @raise [BatchDeleteError] If any of the objects failed to delete,
135
+ # a BatchDeleteError will be raised with a summary of the errors.
136
+ #
137
+ # @return [nil]
138
+ #
139
+ def delete *objects
140
+
141
+ # Detect and retrieve options from the end of the splat.
142
+ if
143
+ objects.size == 2 and
144
+ objects[0].is_a?(Array) and
145
+ objects[1].is_a?(Hash)
146
+ then
147
+ client_opts = objects.pop
148
+ else
149
+ client_opts = {}
150
+ end
151
+
152
+ objects = objects.flatten.collect do |obj|
153
+ case obj
154
+ when String then { :key => obj }
155
+ when Hash then obj
156
+ when S3Object then { :key => obj.key }
157
+ when ObjectVersion then { :key => obj.key, :version_id => obj.version_id }
158
+ else
159
+ msg = "objects must be keys (strings or hashes with :key and " +
160
+ ":version_id), S3Objects or ObjectVersions, got " +
161
+ obj.class.name
162
+ raise ArgumentError, msg
163
+ end
164
+ end
165
+
166
+ batch_helper = BatchHelper.new(1000) do |batch|
167
+ client_opts[:bucket_name] = bucket.name
168
+ client_opts[:quiet] = true
169
+ client_opts[:objects] = batch
170
+ client.delete_objects(client_opts)
171
+ end
172
+
173
+ error_counts = {}
174
+ batch_helper.after_batch do |response|
175
+ response.errors.each do |error|
176
+ error_counts[error.code] ||= 0
177
+ error_counts[error.code] += 1
178
+ end
179
+ end
180
+
181
+ objects.each do |object|
182
+ batch_helper.add(object)
183
+ end
184
+
185
+ batch_helper.complete!
186
+
187
+ raise Errors::BatchDeleteError.new(error_counts) unless
188
+ error_counts.empty?
189
+
190
+ nil
191
+
192
+ end
193
+
194
+ # Deletes each object in the collection that returns a true value
195
+ # from block passed to this method. Deletes are batched for efficiency.
196
+ #
197
+ # # delete text files in the 2009 "folder"
198
+ # bucket.objects.with_prefix('2009/').delete_if {|o| o.key =~ /\.txt$/ }
199
+ #
200
+ # @yieldparam [S3Object] object
201
+ #
202
+ # @raise [BatchDeleteError] If any of the objects failed to delete,
203
+ # a BatchDeleteError will be raised with a summary of the errors.
204
+ #
205
+ def delete_if &block
206
+
207
+ error_counts = {}
208
+
209
+ batch_helper = BatchHelper.new(1000) do |objects|
210
+ begin
211
+ delete(objects)
212
+ rescue Errors::BatchDeleteError => error
213
+ error.error_counts.each_pair do |code,count|
214
+ error_counts[code] ||= 0
215
+ error_counts[code] += count
216
+ end
217
+ end
218
+ end
219
+
220
+ each do |object|
221
+ batch_helper.add(object) if yield(object)
222
+ end
223
+
224
+ batch_helper.complete!
225
+
226
+ raise Errors::BatchDeleteError.new(error_counts) unless
227
+ error_counts.empty?
228
+
229
+ nil
230
+
231
+ end
232
+
233
+ # Deletes all objects represented by this collection.
234
+ #
235
+ # @example Delete all objects from a bucket
236
+ #
237
+ # bucket.objects.delete_all
238
+ #
239
+ # @example Delete objects with a given prefix
240
+ #
241
+ # bucket.objects.with_prefix('2009/').delete_all
242
+ #
243
+ # @raise [BatchDeleteError] If any of the objects failed to delete,
244
+ # a BatchDeleteError will be raised with a summary of the errors.
245
+ #
246
+ # @return [Array] Returns an array of results
247
+ #
248
+ def delete_all
249
+
250
+ error_counts = {}
251
+
252
+ each_batch do |objects|
253
+ begin
254
+ delete(objects)
255
+ rescue Errors::BatchDeleteError => error
256
+ error.error_counts.each_pair do |code,count|
257
+ error_counts[code] ||= 0
258
+ error_counts[code] += count
259
+ end
260
+ end
261
+ end
262
+
263
+ raise Errors::BatchDeleteError.new(error_counts) unless
264
+ error_counts.empty?
265
+
266
+ nil
267
+
268
+ end
269
+
270
+ # Iterates the collection, yielding instances of S3Object.
271
+ #
272
+ # Use break or raise an exception to terminate the enumeration.
273
+ #
274
+ # @param [Hash] options
275
+ # @option options [Integer] :limit (nil) The maximum number of
276
+ # objects to yield.
277
+ # @option options [Integer] :batch_size (1000) The number of objects to
278
+ # fetch each request to S3. Maximum is 1000 keys at time.
279
+ # @return [nil]
280
+ def each options = {}, &block
281
+ super
282
+ end
283
+
284
+ private
285
+
286
+ def each_member_in_page(page, &block)
287
+ super
288
+ page.contents.each do |content|
289
+ content_length = content[:size].to_i if content[:size]
290
+ etag = content[:etag]
291
+ last_modified = content[:last_modified]
292
+ yield(S3Object.new(bucket, content.key, { :content_length => content_length, :etag => etag, :last_modified => last_modified}))
293
+ end
294
+ end
295
+
296
+ def list_request options
297
+ client.list_objects(options)
298
+ end
299
+
300
+ def limit_param
301
+ :max_keys
302
+ end
303
+
304
+ def next_markers page
305
+ if page[:next_marker]
306
+ marker = page[:next_marker]
307
+ elsif page[:contents].size > 0
308
+ marker = page[:contents].last[:key]
309
+ else
310
+ raise 'Unable to find marker in S3 list objects response'
311
+ end
312
+
313
+ { :marker => marker }
314
+ end
315
+
316
+ # processes items in batches of 1k items
317
+ # @api private
318
+ class BatchHelper
319
+
320
+ def initialize batch_size, &block
321
+ @batch_size = batch_size
322
+ @block = block
323
+ @batch = []
324
+ end
325
+
326
+ def after_batch &block
327
+ @after_batch = block
328
+ end
329
+
330
+ def add item
331
+ @batch << item
332
+ if @batch.size == @batch_size
333
+ process_batch
334
+ @batch = []
335
+ end
336
+ item
337
+ end
338
+
339
+ def complete!
340
+ process_batch unless @batch.empty?
341
+ end
342
+
343
+ private
344
+
345
+ def process_batch
346
+ response = @block.call(@batch)
347
+ @after_batch.call(response) if @after_batch
348
+ end
349
+
350
+ end
351
+
352
+ end
353
+
354
+ end
355
+ end
@@ -0,0 +1,102 @@
1
+ # Copyright 2011-2013 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
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ class S3
15
+
16
+ # Returns an object that represents the metadata for an S3 object.
17
+ class ObjectMetadata
18
+
19
+ include Core::Model
20
+
21
+ # @param [S3Object] object
22
+ # @param [Hash] options
23
+ # @option options [String] :version_id A specific version of the object
24
+ # to get metadata for
25
+ def initialize object, options = {}
26
+ @object = object
27
+ @version_id = options[:version_id]
28
+ super
29
+ end
30
+
31
+ # @return [S3Object]
32
+ attr_reader :object
33
+
34
+ # Returns the value for the given name stored in the S3Object's
35
+ # metadata:
36
+ #
37
+ # bucket.objects['myobject'].metadata['purpose']
38
+ # # returns nil if the given metadata key has not been set
39
+ #
40
+ # @param [String,Symbol] name The name of the metadata field to
41
+ # get.
42
+ #
43
+ # @return [String,nil] Returns the metadata for the given name.
44
+ def [] name
45
+ to_h[name.to_s]
46
+ end
47
+
48
+ # Changes the value of the given name stored in the S3Object's
49
+ # metadata:
50
+ #
51
+ # object = bucket.object['myobject']
52
+ # object.metadata['purpose'] = 'research'
53
+ # object.metadata['purpose'] # => 'research'
54
+ #
55
+ # @deprecated In order to safely update an S3 object's metadata, you
56
+ # should use {S3Object#copy_from}. This operation does not preserve
57
+ # the ACL, storage class (standard vs. reduced redundancy) or server
58
+ # side encryption settings. Using this method on anything other than
59
+ # vanilla S3 objects risks clobbering other metadata values set on the
60
+ # object.
61
+ #
62
+ # @note The name and value of each metadata field must conform
63
+ # to US-ASCII.
64
+ #
65
+ # @param [String,Symbol] name The name of the metadata field to
66
+ # set.
67
+ #
68
+ # @param [String] value The new value of the metadata field.
69
+ #
70
+ # @return [String,nil] Returns the value that was set.
71
+ def []= name, value
72
+ raise "cannot change the metadata of an object version; "+
73
+ "use S3Object#write to create a new version with different metadata" if
74
+ @version_id
75
+ metadata = to_h.dup
76
+ metadata[name.to_s] = value
77
+ object.copy_from(object.key,
78
+ :metadata => metadata)
79
+ value
80
+ end
81
+
82
+ # Proxies the method to {#[]}.
83
+ # @return (see #[])
84
+ def method_missing name, *args, &blk
85
+ return super if !args.empty? || blk
86
+ self[name]
87
+ end
88
+
89
+ # @return [Hash] Returns the user-generated metadata stored with
90
+ # this S3 Object.
91
+ def to_h
92
+ options = {}
93
+ options[:bucket_name] = object.bucket.name
94
+ options[:key] = object.key
95
+ options[:version_id] = @version_id if @version_id
96
+ client.head_object(options).meta
97
+ end
98
+
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,76 @@
1
+ # Copyright 2011-2013 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
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ class S3
15
+
16
+ # Represents uploads in progress for a single object.
17
+ #
18
+ # @example Cancel all uploads for an object
19
+ # object.multipart_uploads.each(&:abort)
20
+ #
21
+ # @example Get an upload by ID
22
+ # object.multipart_uploads[id]
23
+ class ObjectUploadCollection
24
+
25
+ include Enumerable
26
+ include Core::Model
27
+
28
+ # @return [S3Object] The object to which the uploads belong.
29
+ attr_reader :object
30
+
31
+ # @api private
32
+ def initialize(object, opts = {})
33
+ @all_uploads =
34
+ MultipartUploadCollection.new(object.bucket).
35
+ with_prefix(object.key)
36
+ @object = object
37
+ super
38
+ end
39
+
40
+ # Creates a new multipart upload. It is usually more
41
+ # convenient to use {S3Object#multipart_upload}.
42
+ def create(options = {})
43
+ options[:storage_class] = :reduced_redundancy if
44
+ options.delete(:reduced_redundancy)
45
+ initiate_opts = {
46
+ :bucket_name => object.bucket.name,
47
+ :key => object.key
48
+ }.merge(options)
49
+ id = client.initiate_multipart_upload(initiate_opts).upload_id
50
+ MultipartUpload.new(object, id)
51
+ end
52
+
53
+ # Iterates the uploads in the collection.
54
+ #
55
+ # @yieldparam [MultipartUpload] upload An upload in the
56
+ # collection.
57
+ # @return [nil]
58
+ def each(options = {}, &block)
59
+ @all_uploads.each(options) do |upload|
60
+ yield(upload) if upload.object.key == @object.key
61
+ end
62
+ nil
63
+ end
64
+
65
+ # @return [MultipartUpload] An object representing the upload
66
+ # with the given ID.
67
+ #
68
+ # @param [String] id The ID of an upload to get.
69
+ #def [] id
70
+ # MultipartUpload.new(object, id)
71
+ #end
72
+
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,153 @@
1
+ # Copyright 2011-2013 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
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ class S3
15
+
16
+ # Represents a single version of an S3Object.
17
+ #
18
+ # When you enable versioning on a S3 bucket, writing to an object
19
+ # will create an object version instead of replacing the existing
20
+ # object.
21
+ class ObjectVersion
22
+
23
+ include Core::Model
24
+
25
+ # @param [S3Object] object The object this is a version of.
26
+ # @param [String] version_id The unique id for this version.
27
+ # @param [Hash] options
28
+ # @option options [Boolean] :delete_marker Is this version a
29
+ # delete marker?
30
+ # @option options [DateTime] :last_modified Date and time the
31
+ # object was last modified.
32
+ def initialize(object, version_id, options = {})
33
+ @object = object
34
+ @version_id = version_id
35
+ @delete_marker = options[:delete_marker]
36
+ @last_modified = options[:last_modified]
37
+ super
38
+ end
39
+
40
+ # @return [S3Object] the object this is a version of.
41
+ attr_reader :object
42
+
43
+ # @return [DateTime] timestamp of this version
44
+ attr_reader :last_modified
45
+
46
+ def bucket
47
+ object.bucket
48
+ end
49
+
50
+ # @return [String] The unique version identifier.
51
+ attr_reader :version_id
52
+
53
+ # @return (see S3Object#key)
54
+ def key
55
+ object.key
56
+ end
57
+
58
+ # (see S3Object#url_for)
59
+ def url_for method, options = {}
60
+ object.url_for(method, options.merge(:version_id => version_id))
61
+ end
62
+
63
+ # @see S3Object#head
64
+ # @return (see S3Object#head)
65
+ def head
66
+ object.head(:version_id => @version_id)
67
+ end
68
+
69
+ # @see S3Object#etag
70
+ # @return (see S3Object#etag)
71
+ def etag
72
+ head.etag
73
+ end
74
+
75
+ # @return (see S3Object#content_length)
76
+ def content_length
77
+ head.content_length
78
+ end
79
+
80
+ # @note (see S3Object#content_type)
81
+ # @see S3Object#content_type
82
+ # @return (see S3Object#content_type)
83
+ def content_type
84
+ head.content_type
85
+ end
86
+
87
+ # @see S3Object#metadata
88
+ # @return (see S3Object#metadata)
89
+ def metadata
90
+ object.metadata(:version_id => @version_id)
91
+ end
92
+
93
+ # Reads the data from this object version.
94
+ # @see S3Object#read
95
+ # @options (see S3Object#read)
96
+ # @return (see S3Object#read)
97
+ def read options = {}, &block
98
+ object.read(options.merge(:version_id => @version_id), &block)
99
+ end
100
+
101
+ # Deletes this object version from S3.
102
+ # @option options [String] :mfa The serial number and current token code of
103
+ # the Multi-Factor Authentication (MFA) device for the user. Format
104
+ # is "SERIAL TOKEN" - with a space between the serial and token.
105
+ # @return (see S3Object#delete)
106
+ def delete(options = {})
107
+ object.delete(:version_id => @version_id,
108
+ :mfa => options[:mfa]
109
+ )
110
+ end
111
+
112
+ # @return [Boolean] Returns this if this is the latest version of
113
+ # the object, false if the object has been written to since
114
+ # this version was created.
115
+ def latest?
116
+ object.versions.latest.version_id == self.version_id
117
+ end
118
+
119
+ # If you delete an object in a versioned bucket, a delete marker
120
+ # is created.
121
+ # @return [Boolean] Returns true if this version is a delete marker.
122
+ def delete_marker?
123
+ if @delete_marker.nil?
124
+ begin
125
+ # S3 responds with a 405 (method not allowed) when you try
126
+ # to HEAD an s3 object version that is a delete marker
127
+ metadata['foo']
128
+ @delete_marker = false
129
+ rescue Errors::MethodNotAllowed => error
130
+ @delete_marker = true
131
+ end
132
+ end
133
+ @delete_marker
134
+ end
135
+
136
+ # @return [Boolean] Returns true if the other object version has
137
+ # the same s3 object key and version id.
138
+ def ==(other)
139
+ other.kind_of?(ObjectVersion) and
140
+ other.object == object and
141
+ other.version_id == version_id
142
+ end
143
+
144
+ alias_method :eql?, :==
145
+
146
+ # @api private
147
+ def inspect
148
+ "<#{self.class}:#{object.bucket.name}:#{object.key}:#{version_id}>"
149
+ end
150
+
151
+ end
152
+ end
153
+ end