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

Side by Side Diff: third_party/gsutil/boto/gs/key.py

Issue 12042069: Scripts to download files from google storage based on sha1 sums (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Removed gsutil/tests and gsutil/docs Created 7 years, 10 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
OLDNEW
(Empty)
1 # Copyright 2010 Google Inc.
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a
4 # copy of this software and associated documentation files (the
5 # "Software"), to deal in the Software without restriction, including
6 # without limitation the rights to use, copy, modify, merge, publish, dis-
7 # tribute, sublicense, and/or sell copies of the Software, and to permit
8 # persons to whom the Software is furnished to do so, subject to the fol-
9 # lowing conditions:
10 #
11 # The above copyright notice and this permission notice shall be included
12 # in all copies or substantial portions of the Software.
13 #
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 # IN THE SOFTWARE.
21
22 import os
23 import StringIO
24 from boto.exception import BotoClientError
25 from boto.s3.key import Key as S3Key
26
27 class Key(S3Key):
28 generation = None
29 meta_generation = None
30
31 def endElement(self, name, value, connection):
32 if name == 'Key':
33 self.name = value
34 elif name == 'ETag':
35 self.etag = value
36 elif name == 'IsLatest':
37 if value == 'true':
38 self.is_latest = True
39 else:
40 self.is_latest = False
41 elif name == 'LastModified':
42 self.last_modified = value
43 elif name == 'Size':
44 self.size = int(value)
45 elif name == 'StorageClass':
46 self.storage_class = value
47 elif name == 'Owner':
48 pass
49 elif name == 'VersionId':
50 self.version_id = value
51 elif name == 'Generation':
52 self.generation = value
53 elif name == 'MetaGeneration':
54 self.meta_generation = value
55 else:
56 setattr(self, name, value)
57
58 def get_file(self, fp, headers=None, cb=None, num_cb=10,
59 torrent=False, version_id=None, override_num_retries=None,
60 response_headers=None):
61 query_args = None
62 if self.generation:
63 query_args = ['generation=%s' % self.generation]
64 self._get_file_internal(fp, headers=headers, cb=cb, num_cb=num_cb,
65 override_num_retries=override_num_retries,
66 response_headers=response_headers,
67 query_args=query_args)
68
69 def delete(self):
70 return self.bucket.delete_key(self.name, version_id=self.version_id,
71 generation=self.generation)
72
73 def add_email_grant(self, permission, email_address):
74 """
75 Convenience method that provides a quick way to add an email grant to a
76 key. This method retrieves the current ACL, creates a new grant based on
77 the parameters passed in, adds that grant to the ACL and then PUT's the
78 new ACL back to GS.
79
80 :type permission: string
81 :param permission: The permission being granted. Should be one of:
82 READ|FULL_CONTROL
83 See http://code.google.com/apis/storage/docs/developer-guide.html#au thorization
84 for more details on permissions.
85
86 :type email_address: string
87 :param email_address: The email address associated with the Google
88 account to which you are granting the permission.
89 """
90 acl = self.get_acl()
91 acl.add_email_grant(permission, email_address)
92 self.set_acl(acl)
93
94 def add_user_grant(self, permission, user_id):
95 """
96 Convenience method that provides a quick way to add a canonical user
97 grant to a key. This method retrieves the current ACL, creates a new
98 grant based on the parameters passed in, adds that grant to the ACL and
99 then PUT's the new ACL back to GS.
100
101 :type permission: string
102 :param permission: The permission being granted. Should be one of:
103 READ|FULL_CONTROL
104 See http://code.google.com/apis/storage/docs/developer-guide.html#au thorization
105 for more details on permissions.
106
107 :type user_id: string
108 :param user_id: The canonical user id associated with the GS account to
109 which you are granting the permission.
110 """
111 acl = self.get_acl()
112 acl.add_user_grant(permission, user_id)
113 self.set_acl(acl)
114
115 def add_group_email_grant(self, permission, email_address, headers=None):
116 """
117 Convenience method that provides a quick way to add an email group
118 grant to a key. This method retrieves the current ACL, creates a new
119 grant based on the parameters passed in, adds that grant to the ACL and
120 then PUT's the new ACL back to GS.
121
122 :type permission: string
123 :param permission: The permission being granted. Should be one of:
124 READ|FULL_CONTROL
125 See http://code.google.com/apis/storage/docs/developer-guide.html#au thorization
126 for more details on permissions.
127
128 :type email_address: string
129 :param email_address: The email address associated with the Google
130 Group to which you are granting the permission.
131 """
132 acl = self.get_acl(headers=headers)
133 acl.add_group_email_grant(permission, email_address)
134 self.set_acl(acl, headers=headers)
135
136 def add_group_grant(self, permission, group_id):
137 """
138 Convenience method that provides a quick way to add a canonical group
139 grant to a key. This method retrieves the current ACL, creates a new
140 grant based on the parameters passed in, adds that grant to the ACL and
141 then PUT's the new ACL back to GS.
142
143 :type permission: string
144 :param permission: The permission being granted. Should be one of:
145 READ|FULL_CONTROL
146 See http://code.google.com/apis/storage/docs/developer-guide.html#au thorization
147 for more details on permissions.
148
149 :type group_id: string
150 :param group_id: The canonical group id associated with the Google
151 Groups account you are granting the permission to.
152 """
153 acl = self.get_acl()
154 acl.add_group_grant(permission, group_id)
155 self.set_acl(acl)
156
157 def set_contents_from_file(self, fp, headers=None, replace=True,
158 cb=None, num_cb=10, policy=None, md5=None,
159 res_upload_handler=None, size=None, rewind=False) :
160 """
161 Store an object in GS using the name of the Key object as the
162 key in GS and the contents of the file pointed to by 'fp' as the
163 contents.
164
165 :type fp: file
166 :param fp: the file whose contents are to be uploaded
167
168 :type headers: dict
169 :param headers: additional HTTP headers to be sent with the PUT request.
170
171 :type replace: bool
172 :param replace: If this parameter is False, the method will first check
173 to see if an object exists in the bucket with the same key. If it
174 does, it won't overwrite it. The default value is True which will
175 overwrite the object.
176
177 :type cb: function
178 :param cb: a callback function that will be called to report
179 progress on the upload. The callback should accept two integer
180 parameters, the first representing the number of bytes that have
181 been successfully transmitted to GS and the second representing the
182 total number of bytes that need to be transmitted.
183
184 :type num_cb: int
185 :param num_cb: (optional) If a callback is specified with the cb
186 parameter, this parameter determines the granularity of the callback
187 by defining the maximum number of times the callback will be called
188 during the file transfer.
189
190 :type policy: :class:`boto.gs.acl.CannedACLStrings`
191 :param policy: A canned ACL policy that will be applied to the new key
192 in GS.
193
194 :type md5: A tuple containing the hexdigest version of the MD5 checksum
195 of the file as the first element and the Base64-encoded version of
196 the plain checksum as the second element. This is the same format
197 returned by the compute_md5 method.
198 :param md5: If you need to compute the MD5 for any reason prior to
199 upload, it's silly to have to do it twice so this param, if present,
200 will be used as the MD5 values of the file. Otherwise, the checksum
201 will be computed.
202
203 :type res_upload_handler: ResumableUploadHandler
204 :param res_upload_handler: If provided, this handler will perform the
205 upload.
206
207 :type size: int
208 :param size: (optional) The Maximum number of bytes to read from
209 the file pointer (fp). This is useful when uploading
210 a file in multiple parts where you are splitting the
211 file up into different ranges to be uploaded. If not
212 specified, the default behaviour is to read all bytes
213 from the file pointer. Less bytes may be available.
214 Notes:
215
216 1. The "size" parameter currently cannot be used when
217 a resumable upload handler is given but is still
218 useful for uploading part of a file as implemented
219 by the parent class.
220 2. At present Google Cloud Storage does not support
221 multipart uploads.
222
223 :type rewind: bool
224 :param rewind: (optional) If True, the file pointer (fp) will be
225 rewound to the start before any bytes are read from
226 it. The default behaviour is False which reads from
227 the current position of the file pointer (fp).
228
229 :rtype: int
230 :return: The number of bytes written to the key.
231
232 TODO: At some point we should refactor the Bucket and Key classes,
233 to move functionality common to all providers into a parent class,
234 and provider-specific functionality into subclasses (rather than
235 just overriding/sharing code the way it currently works).
236 """
237 provider = self.bucket.connection.provider
238 if res_upload_handler and size:
239 # could use size instead of file_length if provided but...
240 raise BotoClientError('"size" param not supported for resumable uplo ads.')
241 headers = headers or {}
242 if policy:
243 headers[provider.acl_header] = policy
244
245 if rewind:
246 # caller requests reading from beginning of fp.
247 fp.seek(0, os.SEEK_SET)
248 else:
249 spos = fp.tell()
250 fp.seek(0, os.SEEK_END)
251 if fp.tell() == spos:
252 fp.seek(0, os.SEEK_SET)
253 if fp.tell() != spos:
254 # Raise an exception as this is likely a programming error
255 # whereby there is data before the fp but nothing after it.
256 fp.seek(spos)
257 raise AttributeError(
258 'fp is at EOF. Use rewind option or seek() to data start.')
259 # seek back to the correct position.
260 fp.seek(spos)
261
262 if hasattr(fp, 'name'):
263 self.path = fp.name
264 if self.bucket != None:
265 if size:
266 self.size = size
267 else:
268 # If md5 is provided, still need to size so
269 # calculate based on bytes to end of content
270 spos = fp.tell()
271 fp.seek(0, os.SEEK_END)
272 self.size = fp.tell() - spos
273 fp.seek(spos)
274 size = self.size
275
276 if self.name == None:
277 if md5 == None:
278 md5 = self.compute_md5(fp, size)
279 self.md5 = md5[0]
280 self.base64md5 = md5[1]
281
282 self.name = self.md5
283 if not replace:
284 if self.bucket.lookup(self.name):
285 return
286 if res_upload_handler:
287 res_upload_handler.send_file(self, fp, headers, cb, num_cb)
288 else:
289 # Not a resumable transfer so use basic send_file mechanism.
290 self.send_file(fp, headers, cb, num_cb, size=size)
291
292 def set_contents_from_filename(self, filename, headers=None, replace=True,
293 cb=None, num_cb=10, policy=None, md5=None,
294 reduced_redundancy=None,
295 res_upload_handler=None):
296 """
297 Store an object in GS using the name of the Key object as the
298 key in GS and the contents of the file named by 'filename'.
299 See set_contents_from_file method for details about the
300 parameters.
301
302 :type filename: string
303 :param filename: The name of the file that you want to put onto GS
304
305 :type headers: dict
306 :param headers: Additional headers to pass along with the request to GS.
307
308 :type replace: bool
309 :param replace: If True, replaces the contents of the file if it
310 already exists.
311
312 :type cb: function
313 :param cb: (optional) a callback function that will be called to report
314 progress on the download. The callback should accept two integer
315 parameters, the first representing the number of bytes that have
316 been successfully transmitted from GS and the second representing
317 the total number of bytes that need to be transmitted.
318
319 :type cb: int
320 :param num_cb: (optional) If a callback is specified with the cb
321 parameter this parameter determines the granularity of the callback
322 by defining the maximum number of times the callback will be called
323 during the file transfer.
324
325 :type policy: :class:`boto.gs.acl.CannedACLStrings`
326 :param policy: A canned ACL policy that will be applied to the new key
327 in GS.
328
329 :type md5: A tuple containing the hexdigest version of the MD5 checksum
330 of the file as the first element and the Base64-encoded version of
331 the plain checksum as the second element. This is the same format
332 returned by the compute_md5 method.
333 :param md5: If you need to compute the MD5 for any reason prior to
334 upload, it's silly to have to do it twice so this param, if present,
335 will be used as the MD5 values of the file. Otherwise, the checksum
336 will be computed.
337
338 :type res_upload_handler: ResumableUploadHandler
339 :param res_upload_handler: If provided, this handler will perform the
340 upload.
341 """
342 # Clear out any previously computed md5 hashes, since we are setting the content.
343 self.md5 = None
344 self.base64md5 = None
345
346 fp = open(filename, 'rb')
347 self.set_contents_from_file(fp, headers, replace, cb, num_cb,
348 policy, md5, res_upload_handler)
349 fp.close()
350
351 def set_contents_from_string(self, s, headers=None, replace=True,
352 cb=None, num_cb=10, policy=None, md5=None):
353 """
354 Store an object in S3 using the name of the Key object as the
355 key in S3 and the string 's' as the contents.
356 See set_contents_from_file method for details about the
357 parameters.
358
359 :type headers: dict
360 :param headers: Additional headers to pass along with the
361 request to AWS.
362
363 :type replace: bool
364 :param replace: If True, replaces the contents of the file if
365 it already exists.
366
367 :type cb: function
368 :param cb: a callback function that will be called to report
369 progress on the upload. The callback should accept
370 two integer parameters, the first representing the
371 number of bytes that have been successfully
372 transmitted to S3 and the second representing the
373 size of the to be transmitted object.
374
375 :type cb: int
376 :param num_cb: (optional) If a callback is specified with
377 the cb parameter this parameter determines the
378 granularity of the callback by defining
379 the maximum number of times the callback will
380 be called during the file transfer.
381
382 :type policy: :class:`boto.s3.acl.CannedACLStrings`
383 :param policy: A canned ACL policy that will be applied to the
384 new key in S3.
385
386 :type md5: A tuple containing the hexdigest version of the MD5
387 checksum of the file as the first element and the
388 Base64-encoded version of the plain checksum as the
389 second element. This is the same format returned by
390 the compute_md5 method.
391 :param md5: If you need to compute the MD5 for any reason prior
392 to upload, it's silly to have to do it twice so this
393 param, if present, will be used as the MD5 values
394 of the file. Otherwise, the checksum will be computed.
395 """
396
397 # Clear out any previously computed md5 hashes, since we are setting the content.
398 self.md5 = None
399 self.base64md5 = None
400
401 if isinstance(s, unicode):
402 s = s.encode("utf-8")
403 fp = StringIO.StringIO(s)
404 r = self.set_contents_from_file(fp, headers, replace, cb, num_cb,
405 policy, md5)
406 fp.close()
407 return r
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698