aws-sdk-resources 2.1.13 → 2.1.14

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c503654019d52649a9d3daef18cbd3b6a0b35c79
4
- data.tar.gz: 17318035e37ee5edb33eda62882c4b7a875d3a14
3
+ metadata.gz: 34475603466832ba05d1de7ada5968455f9751f1
4
+ data.tar.gz: a204f4de98bf6c67d24ac161b279ee17356a2902
5
5
  SHA512:
6
- metadata.gz: a11e6283607c1cc421bfd2a229637c696c9b1641aa004d930e4f7746a074fbdf0b45377dab3c63121ec214679ec45e15e9bb473ab017a172f2fffef7a448ffa9
7
- data.tar.gz: 1de0c0b62ceb783dfd5621c05bd728df686acff1365aee8357542c47fa7bc976cc06607a2b6a55a530be05e8d198c132c8441c5a6249b269e6b5f2cbcd9298ac
6
+ metadata.gz: bda165ec79702fc8ae6b3063be7358dd4ba94cf2e3bc5c0589981ce1866139ed5d014ecf05f570c6cdd4e0e27a8d9c5e2aeb2b7840e3709f4997ca00a0805f5c
7
+ data.tar.gz: d3853941e7d5f3f70429a49fd593a9518b5d39f81c05d609d8e4195bb0167568a59400a85ffe6a5881b740bb109ccd7c3b45899df51864e45c969a153b786258
@@ -187,7 +187,7 @@ module Aws
187
187
  def data_request_param(definition)
188
188
  RequestParams::DataMember.new({
189
189
  target: underscore(definition['target']),
190
- value: underscore(definition['path']),
190
+ path: underscore(definition['path']),
191
191
  })
192
192
  end
193
193
 
@@ -17,6 +17,7 @@ module Aws
17
17
 
18
18
  def apply_customizations
19
19
  document_s3_object_upload_file_additional_options
20
+ document_s3_object_copy_from_options
20
21
  end
21
22
 
22
23
  private
@@ -47,6 +48,46 @@ module Aws
47
48
  tags.each { |tag| m.add_tag(tag) }
48
49
  end
49
50
 
51
+ def document_s3_object_copy_from_options
52
+ copy_from = YARD::Registry['Aws::S3::Object#copy_from']
53
+ copy_to = YARD::Registry['Aws::S3::Object#copy_to']
54
+ existing_tags = copy_from.tags
55
+ copy_from.docstring = 'Copies another object to this object. Use `multipart_copy: true` for large objects. This is required for objects that exceed 5GB.'
56
+ existing_tags.each do |tag|
57
+ if tag.tag_name == 'option' && tag.pair.name != ":copy_source"
58
+ copy_from.add_tag(tag)
59
+ copy_to.add_tag(tag)
60
+ end
61
+ end
62
+ copy_from.add_tag(tag(<<-EXAMPLE))
63
+ @example Basic object copy
64
+
65
+ bucket = Aws::S3::Bucket.new('target-bucket')
66
+ object = bucket.object('target-key')
67
+
68
+ # source as String
69
+ object.copy_from('source-bucket/source-key')
70
+
71
+ # source as Hash
72
+ object.copy_from(bucket:'source-bucket', key:'source-key')
73
+
74
+ # source as Aws::S3::Object
75
+ object.copy_from(bucket.object('source-key'))
76
+ EXAMPLE
77
+
78
+ copy_from.add_tag(tag(<<-EXAMPLE))
79
+ @example Managed copy of large objects
80
+
81
+ # uses multipart upload APIs to copy object
82
+ object.copy_from('src-bucket/src-key', multipart_copy: true)
83
+ EXAMPLE
84
+
85
+ end
86
+
87
+ def tag(string)
88
+ YARD::DocstringParser.new.parse(string).to_docstring.tags.first
89
+ end
90
+
50
91
  end
51
92
  end
52
93
  end
@@ -111,7 +111,7 @@ module Aws
111
111
  include Param
112
112
 
113
113
  def initialize(options)
114
- @path = options[:data_path]
114
+ @path = options[:path]
115
115
  super
116
116
  end
117
117
 
@@ -11,6 +11,8 @@ module Aws
11
11
  autoload :FileUploader, 'aws-sdk-resources/services/s3/file_uploader'
12
12
  autoload :MultipartFileUploader, 'aws-sdk-resources/services/s3/multipart_file_uploader'
13
13
  autoload :MultipartUploadError, 'aws-sdk-resources/services/s3/multipart_upload_error'
14
+ autoload :ObjectCopier, 'aws-sdk-resources/services/s3/object_copier'
15
+ autoload :ObjectMultipartCopier, 'aws-sdk-resources/services/s3/object_multipart_copier'
14
16
  autoload :PresignedPost, 'aws-sdk-resources/services/s3/presigned_post'
15
17
 
16
18
  end
@@ -135,6 +135,63 @@ module Aws
135
135
  options.merge(key: key))
136
136
  end
137
137
 
138
+ # @param [S3::Object, String, Hash] source Where to copy object
139
+ # data from. `source` must be one of the following:
140
+ #
141
+ # * {Aws::S3::Object}
142
+ # * Hash - with `:bucket` and `:key`
143
+ # * String - formatted like `"source-bucket-name/source-key"`
144
+ #
145
+ # @option options [Boolean] :multipart_copy (false) When `true`,
146
+ # the object will be copied using the multipart APIs. This is
147
+ # necessary for objects larger than 5GB and can provide
148
+ # performance improvements on large objects. Amazon S3 does
149
+ # not accept multipart copies for objects smaller than 5MB.
150
+ #
151
+ # @see #copy_to
152
+ #
153
+ def copy_from(source, options = {})
154
+ if Hash === source && source[:copy_source]
155
+ # for backwards compatibility
156
+ @client.copy_object(source.merge(bucket: bucket_name, key: key))
157
+ else
158
+ ObjectCopier.new(self, options).copy_from(source, options)
159
+ end
160
+ end
161
+
162
+ # Copies this object to another object. Use `multipart_copy: true`
163
+ # for large objects. This is required for objects that exceed 5GB.
164
+ #
165
+ # @param [S3::Object, String, Hash] target Where to copy the object
166
+ # data to. `target` must be one of the following:
167
+ #
168
+ # * {Aws::S3::Object}
169
+ # * Hash - with `:bucket` and `:key`
170
+ # * String - formatted like `"target-bucket-name/target-key"`
171
+ #
172
+ # @example Basic object copy
173
+ #
174
+ # bucket = Aws::S3::Bucket.new('source-bucket')
175
+ # object = bucket.object('source-key')
176
+ #
177
+ # # target as String
178
+ # object.copy_to('target-bucket/target-key')
179
+ #
180
+ # # target as Hash
181
+ # object.copy_to(bucket: 'target-bucket', key: 'target-key')
182
+ #
183
+ # # target as Aws::S3::Object
184
+ # object.copy_to(bucket.object('target-key'))
185
+ #
186
+ # @example Managed copy of large objects
187
+ #
188
+ # # uses multipart upload APIs to copy object
189
+ # object.copy_to('src-bucket/src-key', multipart_copy: true)
190
+ #
191
+ def copy_to(target, options = {})
192
+ ObjectCopier.new(self, options).copy_to(target, options)
193
+ end
194
+
138
195
  end
139
196
  end
140
197
  end
@@ -0,0 +1,61 @@
1
+ require 'thread'
2
+
3
+ module Aws
4
+ module S3
5
+ # @api private
6
+ class ObjectCopier
7
+
8
+ # @param [S3::Objecst] object
9
+ def initialize(object, options = {})
10
+ @object = object
11
+ @options = options.merge(client: @object.client)
12
+ end
13
+
14
+ def copy_from(source, options = {})
15
+ copy_object(source, @object, options)
16
+ end
17
+
18
+
19
+ def copy_to(target, options = {})
20
+ copy_object(@object, target, options)
21
+ end
22
+
23
+ private
24
+
25
+ def copy_object(source, target, options)
26
+ target_bucket, target_key = copy_target(target)
27
+ options[:bucket] = target_bucket
28
+ options[:key] = target_key
29
+ options[:copy_source] = copy_source(source)
30
+ if options.delete(:multipart_copy)
31
+ ObjectMultipartCopier.new(@options).copy(options)
32
+ else
33
+ @object.client.copy_object(options)
34
+ end
35
+ end
36
+
37
+ def copy_source(source)
38
+ case source
39
+ when String then source
40
+ when Hash then "#{source[:bucket]}/#{source[:key]}"
41
+ when S3::Object then "#{source.bucket_name}/#{source.key}"
42
+ else
43
+ msg = "expected source to be an Aws::S3::Object, Hash, or String"
44
+ raise ArgumentError, msg
45
+ end
46
+ end
47
+
48
+ def copy_target(target)
49
+ case target
50
+ when String then target.match(/([^\/]+?)\/(.+)/)[1,2]
51
+ when Hash then target.values_at(:bucket, :key)
52
+ when S3::Object then [target.bucket_name, target.key]
53
+ else
54
+ msg = "expected target to be an Aws::S3::Object, Hash, or String"
55
+ raise ArgumentError, msg
56
+ end
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,171 @@
1
+ require 'thread'
2
+
3
+ module Aws
4
+ module S3
5
+ # @api private
6
+ class ObjectMultipartCopier
7
+
8
+ FIVE_MB = 5 * 1024 * 1024 # 5MB
9
+
10
+ FILE_TOO_SMALL = "unable to multipart copy files smaller than 5MB"
11
+
12
+ MAX_PARTS = 10_000
13
+
14
+ # @option options [Client] :client
15
+ # @option [Integer] :min_part_size (52428800) Size of copied parts.
16
+ # Defaults to 50MB.
17
+ # will be constructed from the given `options' hash.
18
+ # @option [Integer] :thread_count (10) Number of concurrent threads to
19
+ # use for copying parts.
20
+ def initialize(options = {})
21
+ @thread_count = options.delete(:thread_count) || 10
22
+ @min_part_size = options.delete(:min_part_size) || (FIVE_MB * 10)
23
+ @client = options[:client] || Client.new
24
+ end
25
+
26
+ # @return [Client]
27
+ attr_reader :client
28
+
29
+ # @option (see S3::Client#copy_object)
30
+ def copy(options = {})
31
+ size = source_size(options)
32
+ options[:upload_id] = initiate_upload(options)
33
+ begin
34
+ parts = copy_parts(size, default_part_size(size), options)
35
+ complete_upload(parts, options)
36
+ rescue => error
37
+ abort_upload(options)
38
+ raise error
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def initiate_upload(options)
45
+ options = options_for(:create_multipart_upload, options)
46
+ @client.create_multipart_upload(options).upload_id
47
+ end
48
+
49
+ def copy_parts(size, default_part_size, options)
50
+ queue = PartQueue.new(compute_parts(size, default_part_size, options))
51
+ threads = []
52
+ @thread_count.times do
53
+ threads << copy_part_thread(queue)
54
+ end
55
+ threads.map(&:value).flatten.sort_by{ |part| part[:part_number] }
56
+ end
57
+
58
+ def copy_part_thread(queue)
59
+ Thread.new do
60
+ begin
61
+ completed = []
62
+ while part = queue.shift
63
+ completed << copy_part(part)
64
+ end
65
+ completed
66
+ rescue => error
67
+ queue.clear!
68
+ raise error
69
+ end
70
+ end
71
+ end
72
+
73
+ def copy_part(part)
74
+ {
75
+ etag: @client.upload_part_copy(part).copy_part_result.etag,
76
+ part_number: part[:part_number],
77
+ }
78
+ end
79
+
80
+ def complete_upload(parts, options)
81
+ options = options_for(:complete_multipart_upload, options)
82
+ options[:multipart_upload] = { parts: parts }
83
+ @client.complete_multipart_upload(options)
84
+ end
85
+
86
+ def abort_upload(options)
87
+ @client.abort_multipart_upload({
88
+ bucket: options[:bucket],
89
+ key: options[:key],
90
+ upload_id: options[:upload_id],
91
+ })
92
+ end
93
+
94
+ def compute_parts(size, default_part_size, options)
95
+ part_number = 1
96
+ offset = 0
97
+ parts = []
98
+ options = options_for(:upload_part_copy, options)
99
+ while offset < size
100
+ parts << options.merge({
101
+ part_number: part_number,
102
+ copy_source_range: byte_range(offset, default_part_size, size),
103
+ })
104
+ part_number += 1
105
+ offset += default_part_size
106
+ end
107
+ parts
108
+ end
109
+
110
+ def byte_range(offset, default_part_size, size)
111
+ if offset + default_part_size < size
112
+ "bytes=#{offset}-#{offset + default_part_size - 1}"
113
+ else
114
+ "bytes=#{offset}-#{size - 1}"
115
+ end
116
+ end
117
+
118
+ def source_size(options)
119
+ if options[:content_length]
120
+ options.delete(:content_length)
121
+ else
122
+ bucket, key = options[:copy_source].match(/([^\/]+?)\/(.+)/)[1,2]
123
+ @client.head_object(bucket:bucket, key:key).content_length
124
+ end
125
+ end
126
+
127
+ def default_part_size(source_size)
128
+ if source_size < FIVE_MB
129
+ raise ArgumentError, FILE_TOO_SMALL
130
+ else
131
+ [(source_size.to_f / MAX_PARTS).ceil, @min_part_size].max.to_i
132
+ end
133
+ end
134
+
135
+ def options_for(operation_name, options)
136
+ API_OPTIONS[operation_name].inject({}) do |hash, opt_name|
137
+ hash[opt_name] = options[opt_name] if options.key?(opt_name)
138
+ hash
139
+ end
140
+ end
141
+
142
+ # @api private
143
+ def self.options_for(shape_name)
144
+ Client.api.metadata['shapes'][shape_name].member_names
145
+ end
146
+
147
+ API_OPTIONS = {
148
+ create_multipart_upload: options_for('CreateMultipartUploadRequest'),
149
+ upload_part_copy: options_for('UploadPartCopyRequest'),
150
+ complete_multipart_upload: options_for('CompleteMultipartUploadRequest'),
151
+ }
152
+
153
+ class PartQueue
154
+
155
+ def initialize(parts = [])
156
+ @parts = parts
157
+ @mutex = Mutex.new
158
+ end
159
+
160
+ def shift
161
+ @mutex.synchronize { @parts.shift }
162
+ end
163
+
164
+ def clear!
165
+ @mutex.synchronize { @parts.clear }
166
+ end
167
+
168
+ end
169
+ end
170
+ end
171
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-sdk-resources
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.13
4
+ version: 2.1.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amazon Web Services
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-06 00:00:00.000000000 Z
11
+ date: 2015-08-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-core
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 2.1.13
19
+ version: 2.1.14
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 2.1.13
26
+ version: 2.1.14
27
27
  description: Provides resource oriented interfaces and other higher-level abstractions
28
28
  for many AWS services. This gem is part of the official AWS SDK for Ruby.
29
29
  email:
@@ -77,6 +77,8 @@ files:
77
77
  - lib/aws-sdk-resources/services/s3/multipart_upload.rb
78
78
  - lib/aws-sdk-resources/services/s3/multipart_upload_error.rb
79
79
  - lib/aws-sdk-resources/services/s3/object.rb
80
+ - lib/aws-sdk-resources/services/s3/object_copier.rb
81
+ - lib/aws-sdk-resources/services/s3/object_multipart_copier.rb
80
82
  - lib/aws-sdk-resources/services/s3/object_summary.rb
81
83
  - lib/aws-sdk-resources/services/s3/presigned_post.rb
82
84
  - lib/aws-sdk-resources/services/sns.rb
@@ -104,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
106
  version: '0'
105
107
  requirements: []
106
108
  rubyforge_project:
107
- rubygems_version: 2.4.6
109
+ rubygems_version: 2.5.0
108
110
  signing_key:
109
111
  specification_version: 4
110
112
  summary: AWS SDK for Ruby - Resources