Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(97)

Side by Side Diff: third_party/boto/s3/multipart.py

Issue 12633019: Added boto/ to depot_tools/third_party (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Moved boto down by one Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/boto/s3/multidelete.py ('k') | third_party/boto/s3/prefix.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright (c) 2006-2012 Mitch Garnaat http://garnaat.org/
2 # Copyright (c) 2012 Amazon.com, Inc. or its affiliates.
3 # Copyright (c) 2010, Eucalyptus Systems, Inc.
4 # All Rights Reserved
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a
7 # copy of this software and associated documentation files (the
8 # "Software"), to deal in the Software without restriction, including
9 # without limitation the rights to use, copy, modify, merge, publish, dis-
10 # tribute, sublicense, and/or sell copies of the Software, and to permit
11 # persons to whom the Software is furnished to do so, subject to the fol-
12 # lowing conditions:
13 #
14 # The above copyright notice and this permission notice shall be included
15 # in all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
19 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
20 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 # IN THE SOFTWARE.
24
25 import user
26 import key
27 from boto import handler
28 import xml.sax
29
30
31 class CompleteMultiPartUpload(object):
32 """
33 Represents a completed MultiPart Upload. Contains the
34 following useful attributes:
35
36 * location - The URI of the completed upload
37 * bucket_name - The name of the bucket in which the upload
38 is contained
39 * key_name - The name of the new, completed key
40 * etag - The MD5 hash of the completed, combined upload
41 * version_id - The version_id of the completed upload
42 * encrypted - The value of the encryption header
43 """
44
45 def __init__(self, bucket=None):
46 self.bucket = bucket
47 self.location = None
48 self.bucket_name = None
49 self.key_name = None
50 self.etag = None
51 self.version_id = None
52 self.encrypted = None
53
54 def __repr__(self):
55 return '<CompleteMultiPartUpload: %s.%s>' % (self.bucket_name,
56 self.key_name)
57
58 def startElement(self, name, attrs, connection):
59 return None
60
61 def endElement(self, name, value, connection):
62 if name == 'Location':
63 self.location = value
64 elif name == 'Bucket':
65 self.bucket_name = value
66 elif name == 'Key':
67 self.key_name = value
68 elif name == 'ETag':
69 self.etag = value
70 else:
71 setattr(self, name, value)
72
73
74 class Part(object):
75 """
76 Represents a single part in a MultiPart upload.
77 Attributes include:
78
79 * part_number - The integer part number
80 * last_modified - The last modified date of this part
81 * etag - The MD5 hash of this part
82 * size - The size, in bytes, of this part
83 """
84
85 def __init__(self, bucket=None):
86 self.bucket = bucket
87 self.part_number = None
88 self.last_modified = None
89 self.etag = None
90 self.size = None
91
92 def __repr__(self):
93 if isinstance(self.part_number, int):
94 return '<Part %d>' % self.part_number
95 else:
96 return '<Part %s>' % None
97
98 def startElement(self, name, attrs, connection):
99 return None
100
101 def endElement(self, name, value, connection):
102 if name == 'PartNumber':
103 self.part_number = int(value)
104 elif name == 'LastModified':
105 self.last_modified = value
106 elif name == 'ETag':
107 self.etag = value
108 elif name == 'Size':
109 self.size = int(value)
110 else:
111 setattr(self, name, value)
112
113
114 def part_lister(mpupload, part_number_marker=None):
115 """
116 A generator function for listing parts of a multipart upload.
117 """
118 more_results = True
119 part = None
120 while more_results:
121 parts = mpupload.get_all_parts(None, part_number_marker)
122 for part in parts:
123 yield part
124 part_number_marker = mpupload.next_part_number_marker
125 more_results = mpupload.is_truncated
126
127
128 class MultiPartUpload(object):
129 """
130 Represents a MultiPart Upload operation.
131 """
132
133 def __init__(self, bucket=None):
134 self.bucket = bucket
135 self.bucket_name = None
136 self.key_name = None
137 self.id = id
138 self.initiator = None
139 self.owner = None
140 self.storage_class = None
141 self.initiated = None
142 self.part_number_marker = None
143 self.next_part_number_marker = None
144 self.max_parts = None
145 self.is_truncated = False
146 self._parts = None
147
148 def __repr__(self):
149 return '<MultiPartUpload %s>' % self.key_name
150
151 def __iter__(self):
152 return part_lister(self)
153
154 def to_xml(self):
155 s = '<CompleteMultipartUpload>\n'
156 for part in self:
157 s += ' <Part>\n'
158 s += ' <PartNumber>%d</PartNumber>\n' % part.part_number
159 s += ' <ETag>%s</ETag>\n' % part.etag
160 s += ' </Part>\n'
161 s += '</CompleteMultipartUpload>'
162 return s
163
164 def startElement(self, name, attrs, connection):
165 if name == 'Initiator':
166 self.initiator = user.User(self)
167 return self.initiator
168 elif name == 'Owner':
169 self.owner = user.User(self)
170 return self.owner
171 elif name == 'Part':
172 part = Part(self.bucket)
173 self._parts.append(part)
174 return part
175 return None
176
177 def endElement(self, name, value, connection):
178 if name == 'Bucket':
179 self.bucket_name = value
180 elif name == 'Key':
181 self.key_name = value
182 elif name == 'UploadId':
183 self.id = value
184 elif name == 'StorageClass':
185 self.storage_class = value
186 elif name == 'PartNumberMarker':
187 self.part_number_marker = value
188 elif name == 'NextPartNumberMarker':
189 self.next_part_number_marker = value
190 elif name == 'MaxParts':
191 self.max_parts = int(value)
192 elif name == 'IsTruncated':
193 if value == 'true':
194 self.is_truncated = True
195 else:
196 self.is_truncated = False
197 elif name == 'Initiated':
198 self.initiated = value
199 else:
200 setattr(self, name, value)
201
202 def get_all_parts(self, max_parts=None, part_number_marker=None):
203 """
204 Return the uploaded parts of this MultiPart Upload. This is
205 a lower-level method that requires you to manually page through
206 results. To simplify this process, you can just use the
207 object itself as an iterator and it will automatically handle
208 all of the paging with S3.
209 """
210 self._parts = []
211 query_args = 'uploadId=%s' % self.id
212 if max_parts:
213 query_args += '&max-parts=%d' % max_parts
214 if part_number_marker:
215 query_args += '&part-number-marker=%s' % part_number_marker
216 response = self.bucket.connection.make_request('GET', self.bucket.name,
217 self.key_name,
218 query_args=query_args)
219 body = response.read()
220 if response.status == 200:
221 h = handler.XmlHandler(self, self)
222 xml.sax.parseString(body, h)
223 return self._parts
224
225 def upload_part_from_file(self, fp, part_num, headers=None, replace=True,
226 cb=None, num_cb=10, md5=None, size=None):
227 """
228 Upload another part of this MultiPart Upload.
229
230 :type fp: file
231 :param fp: The file object you want to upload.
232
233 :type part_num: int
234 :param part_num: The number of this part.
235
236 The other parameters are exactly as defined for the
237 :class:`boto.s3.key.Key` set_contents_from_file method.
238 """
239 if part_num < 1:
240 raise ValueError('Part numbers must be greater than zero')
241 query_args = 'uploadId=%s&partNumber=%d' % (self.id, part_num)
242 key = self.bucket.new_key(self.key_name)
243 key.set_contents_from_file(fp, headers=headers, replace=replace,
244 cb=cb, num_cb=num_cb, md5=md5,
245 reduced_redundancy=False,
246 query_args=query_args, size=size)
247
248 def copy_part_from_key(self, src_bucket_name, src_key_name, part_num,
249 start=None, end=None, src_version_id=None,
250 headers=None):
251 """
252 Copy another part of this MultiPart Upload.
253
254 :type src_bucket_name: string
255 :param src_bucket_name: Name of the bucket containing the source key
256
257 :type src_key_name: string
258 :param src_key_name: Name of the source key
259
260 :type part_num: int
261 :param part_num: The number of this part.
262
263 :type start: int
264 :param start: Zero-based byte offset to start copying from
265
266 :type end: int
267 :param end: Zero-based byte offset to copy to
268
269 :type src_version_id: string
270 :param src_version_id: version_id of source object to copy from
271
272 :type headers: dict
273 :param headers: Any headers to pass along in the request
274 """
275 if part_num < 1:
276 raise ValueError('Part numbers must be greater than zero')
277 query_args = 'uploadId=%s&partNumber=%d' % (self.id, part_num)
278 if start is not None and end is not None:
279 rng = 'bytes=%s-%s' % (start, end)
280 provider = self.bucket.connection.provider
281 if headers is None:
282 headers = {}
283 else:
284 headers = headers.copy()
285 headers[provider.copy_source_range_header] = rng
286 return self.bucket.copy_key(self.key_name, src_bucket_name,
287 src_key_name,
288 src_version_id=src_version_id,
289 storage_class=None,
290 headers=headers,
291 query_args=query_args)
292
293 def complete_upload(self):
294 """
295 Complete the MultiPart Upload operation. This method should
296 be called when all parts of the file have been successfully
297 uploaded to S3.
298
299 :rtype: :class:`boto.s3.multipart.CompletedMultiPartUpload`
300 :returns: An object representing the completed upload.
301 """
302 xml = self.to_xml()
303 return self.bucket.complete_multipart_upload(self.key_name,
304 self.id, xml)
305
306 def cancel_upload(self):
307 """
308 Cancels a MultiPart Upload operation. The storage consumed by
309 any previously uploaded parts will be freed. However, if any
310 part uploads are currently in progress, those part uploads
311 might or might not succeed. As a result, it might be necessary
312 to abort a given multipart upload multiple times in order to
313 completely free all storage consumed by all parts.
314 """
315 self.bucket.cancel_multipart_upload(self.key_name, self.id)
OLDNEW
« no previous file with comments | « third_party/boto/s3/multidelete.py ('k') | third_party/boto/s3/prefix.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698