OLD | NEW |
(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 base64 |
| 23 import binascii |
| 24 import os |
| 25 import re |
| 26 import StringIO |
| 27 from boto.exception import BotoClientError |
| 28 from boto.s3.key import Key as S3Key |
| 29 from boto.s3.keyfile import KeyFile |
| 30 |
| 31 class Key(S3Key): |
| 32 """ |
| 33 Represents a key (object) in a GS bucket. |
| 34 |
| 35 :ivar bucket: The parent :class:`boto.gs.bucket.Bucket`. |
| 36 :ivar name: The name of this Key object. |
| 37 :ivar metadata: A dictionary containing user metadata that you |
| 38 wish to store with the object or that has been retrieved from |
| 39 an existing object. |
| 40 :ivar cache_control: The value of the `Cache-Control` HTTP header. |
| 41 :ivar content_type: The value of the `Content-Type` HTTP header. |
| 42 :ivar content_encoding: The value of the `Content-Encoding` HTTP header. |
| 43 :ivar content_disposition: The value of the `Content-Disposition` HTTP |
| 44 header. |
| 45 :ivar content_language: The value of the `Content-Language` HTTP header. |
| 46 :ivar etag: The `etag` associated with this object. |
| 47 :ivar last_modified: The string timestamp representing the last |
| 48 time this object was modified in GS. |
| 49 :ivar owner: The ID of the owner of this object. |
| 50 :ivar storage_class: The storage class of the object. Currently, one of: |
| 51 STANDARD | DURABLE_REDUCED_AVAILABILITY. |
| 52 :ivar md5: The MD5 hash of the contents of the object. |
| 53 :ivar size: The size, in bytes, of the object. |
| 54 :ivar generation: The generation number of the object. |
| 55 :ivar meta_generation: The generation number of the object metadata. |
| 56 :ivar encrypted: Whether the object is encrypted while at rest on |
| 57 the server. |
| 58 """ |
| 59 generation = None |
| 60 meta_generation = None |
| 61 |
| 62 def __repr__(self): |
| 63 if self.generation and self.meta_generation: |
| 64 ver_str = '#%s.%s' % (self.generation, self.meta_generation) |
| 65 else: |
| 66 ver_str = '' |
| 67 if self.bucket: |
| 68 return '<Key: %s,%s%s>' % (self.bucket.name, self.name, ver_str) |
| 69 else: |
| 70 return '<Key: None,%s%s>' % (self.name, ver_str) |
| 71 |
| 72 def endElement(self, name, value, connection): |
| 73 if name == 'Key': |
| 74 self.name = value |
| 75 elif name == 'ETag': |
| 76 self.etag = value |
| 77 elif name == 'IsLatest': |
| 78 if value == 'true': |
| 79 self.is_latest = True |
| 80 else: |
| 81 self.is_latest = False |
| 82 elif name == 'LastModified': |
| 83 self.last_modified = value |
| 84 elif name == 'Size': |
| 85 self.size = int(value) |
| 86 elif name == 'StorageClass': |
| 87 self.storage_class = value |
| 88 elif name == 'Owner': |
| 89 pass |
| 90 elif name == 'VersionId': |
| 91 self.version_id = value |
| 92 elif name == 'Generation': |
| 93 self.generation = value |
| 94 elif name == 'MetaGeneration': |
| 95 self.meta_generation = value |
| 96 else: |
| 97 setattr(self, name, value) |
| 98 |
| 99 def handle_version_headers(self, resp, force=False): |
| 100 self.meta_generation = resp.getheader('x-goog-metageneration', None) |
| 101 self.generation = resp.getheader('x-goog-generation', None) |
| 102 |
| 103 def get_file(self, fp, headers=None, cb=None, num_cb=10, |
| 104 torrent=False, version_id=None, override_num_retries=None, |
| 105 response_headers=None): |
| 106 query_args = None |
| 107 if self.generation: |
| 108 query_args = ['generation=%s' % self.generation] |
| 109 self._get_file_internal(fp, headers=headers, cb=cb, num_cb=num_cb, |
| 110 override_num_retries=override_num_retries, |
| 111 response_headers=response_headers, |
| 112 query_args=query_args) |
| 113 |
| 114 def delete(self): |
| 115 return self.bucket.delete_key(self.name, version_id=self.version_id, |
| 116 generation=self.generation) |
| 117 |
| 118 def add_email_grant(self, permission, email_address): |
| 119 """ |
| 120 Convenience method that provides a quick way to add an email grant to a |
| 121 key. This method retrieves the current ACL, creates a new grant based on |
| 122 the parameters passed in, adds that grant to the ACL and then PUT's the |
| 123 new ACL back to GS. |
| 124 |
| 125 :type permission: string |
| 126 :param permission: The permission being granted. Should be one of: |
| 127 READ|FULL_CONTROL |
| 128 See http://code.google.com/apis/storage/docs/developer-guide.html#au
thorization |
| 129 for more details on permissions. |
| 130 |
| 131 :type email_address: string |
| 132 :param email_address: The email address associated with the Google |
| 133 account to which you are granting the permission. |
| 134 """ |
| 135 acl = self.get_acl() |
| 136 acl.add_email_grant(permission, email_address) |
| 137 self.set_acl(acl) |
| 138 |
| 139 def add_user_grant(self, permission, user_id): |
| 140 """ |
| 141 Convenience method that provides a quick way to add a canonical user |
| 142 grant to a key. This method retrieves the current ACL, creates a new |
| 143 grant based on the parameters passed in, adds that grant to the ACL and |
| 144 then PUT's the new ACL back to GS. |
| 145 |
| 146 :type permission: string |
| 147 :param permission: The permission being granted. Should be one of: |
| 148 READ|FULL_CONTROL |
| 149 See http://code.google.com/apis/storage/docs/developer-guide.html#au
thorization |
| 150 for more details on permissions. |
| 151 |
| 152 :type user_id: string |
| 153 :param user_id: The canonical user id associated with the GS account to |
| 154 which you are granting the permission. |
| 155 """ |
| 156 acl = self.get_acl() |
| 157 acl.add_user_grant(permission, user_id) |
| 158 self.set_acl(acl) |
| 159 |
| 160 def add_group_email_grant(self, permission, email_address, headers=None): |
| 161 """ |
| 162 Convenience method that provides a quick way to add an email group |
| 163 grant to a key. This method retrieves the current ACL, creates a new |
| 164 grant based on the parameters passed in, adds that grant to the ACL and |
| 165 then PUT's the new ACL back to GS. |
| 166 |
| 167 :type permission: string |
| 168 :param permission: The permission being granted. Should be one of: |
| 169 READ|FULL_CONTROL |
| 170 See http://code.google.com/apis/storage/docs/developer-guide.html#au
thorization |
| 171 for more details on permissions. |
| 172 |
| 173 :type email_address: string |
| 174 :param email_address: The email address associated with the Google |
| 175 Group to which you are granting the permission. |
| 176 """ |
| 177 acl = self.get_acl(headers=headers) |
| 178 acl.add_group_email_grant(permission, email_address) |
| 179 self.set_acl(acl, headers=headers) |
| 180 |
| 181 def add_group_grant(self, permission, group_id): |
| 182 """ |
| 183 Convenience method that provides a quick way to add a canonical group |
| 184 grant to a key. This method retrieves the current ACL, creates a new |
| 185 grant based on the parameters passed in, adds that grant to the ACL and |
| 186 then PUT's the new ACL back to GS. |
| 187 |
| 188 :type permission: string |
| 189 :param permission: The permission being granted. Should be one of: |
| 190 READ|FULL_CONTROL |
| 191 See http://code.google.com/apis/storage/docs/developer-guide.html#au
thorization |
| 192 for more details on permissions. |
| 193 |
| 194 :type group_id: string |
| 195 :param group_id: The canonical group id associated with the Google |
| 196 Groups account you are granting the permission to. |
| 197 """ |
| 198 acl = self.get_acl() |
| 199 acl.add_group_grant(permission, group_id) |
| 200 self.set_acl(acl) |
| 201 |
| 202 def set_contents_from_file(self, fp, headers=None, replace=True, |
| 203 cb=None, num_cb=10, policy=None, md5=None, |
| 204 res_upload_handler=None, size=None, rewind=False, |
| 205 if_generation=None): |
| 206 """ |
| 207 Store an object in GS using the name of the Key object as the |
| 208 key in GS and the contents of the file pointed to by 'fp' as the |
| 209 contents. |
| 210 |
| 211 :type fp: file |
| 212 :param fp: the file whose contents are to be uploaded |
| 213 |
| 214 :type headers: dict |
| 215 :param headers: additional HTTP headers to be sent with the PUT request. |
| 216 |
| 217 :type replace: bool |
| 218 :param replace: If this parameter is False, the method will first check |
| 219 to see if an object exists in the bucket with the same key. If it |
| 220 does, it won't overwrite it. The default value is True which will |
| 221 overwrite the object. |
| 222 |
| 223 :type cb: function |
| 224 :param cb: a callback function that will be called to report |
| 225 progress on the upload. The callback should accept two integer |
| 226 parameters, the first representing the number of bytes that have |
| 227 been successfully transmitted to GS and the second representing the |
| 228 total number of bytes that need to be transmitted. |
| 229 |
| 230 :type num_cb: int |
| 231 :param num_cb: (optional) If a callback is specified with the cb |
| 232 parameter, this parameter determines the granularity of the callback |
| 233 by defining the maximum number of times the callback will be called |
| 234 during the file transfer. |
| 235 |
| 236 :type policy: :class:`boto.gs.acl.CannedACLStrings` |
| 237 :param policy: A canned ACL policy that will be applied to the new key |
| 238 in GS. |
| 239 |
| 240 :type md5: A tuple containing the hexdigest version of the MD5 checksum |
| 241 of the file as the first element and the Base64-encoded version of |
| 242 the plain checksum as the second element. This is the same format |
| 243 returned by the compute_md5 method. |
| 244 :param md5: If you need to compute the MD5 for any reason prior to |
| 245 upload, it's silly to have to do it twice so this param, if present, |
| 246 will be used as the MD5 values of the file. Otherwise, the checksum |
| 247 will be computed. |
| 248 |
| 249 :type res_upload_handler: ResumableUploadHandler |
| 250 :param res_upload_handler: If provided, this handler will perform the |
| 251 upload. |
| 252 |
| 253 :type size: int |
| 254 :param size: (optional) The Maximum number of bytes to read from |
| 255 the file pointer (fp). This is useful when uploading |
| 256 a file in multiple parts where you are splitting the |
| 257 file up into different ranges to be uploaded. If not |
| 258 specified, the default behaviour is to read all bytes |
| 259 from the file pointer. Less bytes may be available. |
| 260 Notes: |
| 261 |
| 262 1. The "size" parameter currently cannot be used when |
| 263 a resumable upload handler is given but is still |
| 264 useful for uploading part of a file as implemented |
| 265 by the parent class. |
| 266 2. At present Google Cloud Storage does not support |
| 267 multipart uploads. |
| 268 |
| 269 :type rewind: bool |
| 270 :param rewind: (optional) If True, the file pointer (fp) will be |
| 271 rewound to the start before any bytes are read from |
| 272 it. The default behaviour is False which reads from |
| 273 the current position of the file pointer (fp). |
| 274 |
| 275 :type if_generation: int |
| 276 :param if_generation: (optional) If set to a generation number, the |
| 277 object will only be written to if its current generation number is |
| 278 this value. If set to the value 0, the object will only be written |
| 279 if it doesn't already exist. |
| 280 |
| 281 :rtype: int |
| 282 :return: The number of bytes written to the key. |
| 283 |
| 284 TODO: At some point we should refactor the Bucket and Key classes, |
| 285 to move functionality common to all providers into a parent class, |
| 286 and provider-specific functionality into subclasses (rather than |
| 287 just overriding/sharing code the way it currently works). |
| 288 """ |
| 289 provider = self.bucket.connection.provider |
| 290 if res_upload_handler and size: |
| 291 # could use size instead of file_length if provided but... |
| 292 raise BotoClientError('"size" param not supported for resumable uplo
ads.') |
| 293 headers = headers or {} |
| 294 if policy: |
| 295 headers[provider.acl_header] = policy |
| 296 |
| 297 if rewind: |
| 298 # caller requests reading from beginning of fp. |
| 299 fp.seek(0, os.SEEK_SET) |
| 300 else: |
| 301 # The following seek/tell/seek logic is intended |
| 302 # to detect applications using the older interface to |
| 303 # set_contents_from_file(), which automatically rewound the |
| 304 # file each time the Key was reused. This changed with commit |
| 305 # 14ee2d03f4665fe20d19a85286f78d39d924237e, to support uploads |
| 306 # split into multiple parts and uploaded in parallel, and at |
| 307 # the time of that commit this check was added because otherwise |
| 308 # older programs would get a success status and upload an empty |
| 309 # object. Unfortuantely, it's very inefficient for fp's implemented |
| 310 # by KeyFile (used, for example, by gsutil when copying between |
| 311 # providers). So, we skip the check for the KeyFile case. |
| 312 # TODO: At some point consider removing this seek/tell/seek |
| 313 # logic, after enough time has passed that it's unlikely any |
| 314 # programs remain that assume the older auto-rewind interface. |
| 315 if not isinstance(fp, KeyFile): |
| 316 spos = fp.tell() |
| 317 fp.seek(0, os.SEEK_END) |
| 318 if fp.tell() == spos: |
| 319 fp.seek(0, os.SEEK_SET) |
| 320 if fp.tell() != spos: |
| 321 # Raise an exception as this is likely a programming |
| 322 # error whereby there is data before the fp but nothing |
| 323 # after it. |
| 324 fp.seek(spos) |
| 325 raise AttributeError('fp is at EOF. Use rewind option ' |
| 326 'or seek() to data start.') |
| 327 # seek back to the correct position. |
| 328 fp.seek(spos) |
| 329 |
| 330 if hasattr(fp, 'name'): |
| 331 self.path = fp.name |
| 332 if self.bucket != None: |
| 333 if isinstance(fp, KeyFile): |
| 334 # Avoid EOF seek for KeyFile case as it's very inefficient. |
| 335 key = fp.getkey() |
| 336 size = key.size - fp.tell() |
| 337 self.size = size |
| 338 # At present both GCS and S3 use MD5 for the etag for |
| 339 # non-multipart-uploaded objects. If the etag is 32 hex |
| 340 # chars use it as an MD5, to avoid having to read the file |
| 341 # twice while transferring. |
| 342 if (re.match('^"[a-fA-F0-9]{32}"$', key.etag)): |
| 343 etag = key.etag.strip('"') |
| 344 md5 = (etag, base64.b64encode(binascii.unhexlify(etag))) |
| 345 if size: |
| 346 self.size = size |
| 347 else: |
| 348 # If md5 is provided, still need to size so |
| 349 # calculate based on bytes to end of content |
| 350 spos = fp.tell() |
| 351 fp.seek(0, os.SEEK_END) |
| 352 self.size = fp.tell() - spos |
| 353 fp.seek(spos) |
| 354 size = self.size |
| 355 |
| 356 if md5 == None: |
| 357 md5 = self.compute_md5(fp, size) |
| 358 self.md5 = md5[0] |
| 359 self.base64md5 = md5[1] |
| 360 |
| 361 if self.name == None: |
| 362 self.name = self.md5 |
| 363 |
| 364 if not replace: |
| 365 if self.bucket.lookup(self.name): |
| 366 return |
| 367 |
| 368 if if_generation is not None: |
| 369 headers['x-goog-if-generation-match'] = str(if_generation) |
| 370 |
| 371 if res_upload_handler: |
| 372 res_upload_handler.send_file(self, fp, headers, cb, num_cb) |
| 373 else: |
| 374 # Not a resumable transfer so use basic send_file mechanism. |
| 375 self.send_file(fp, headers, cb, num_cb, size=size) |
| 376 |
| 377 def set_contents_from_filename(self, filename, headers=None, replace=True, |
| 378 cb=None, num_cb=10, policy=None, md5=None, |
| 379 reduced_redundancy=None, |
| 380 res_upload_handler=None, |
| 381 if_generation=None): |
| 382 """ |
| 383 Store an object in GS using the name of the Key object as the |
| 384 key in GS and the contents of the file named by 'filename'. |
| 385 See set_contents_from_file method for details about the |
| 386 parameters. |
| 387 |
| 388 :type filename: string |
| 389 :param filename: The name of the file that you want to put onto GS |
| 390 |
| 391 :type headers: dict |
| 392 :param headers: Additional headers to pass along with the request to GS. |
| 393 |
| 394 :type replace: bool |
| 395 :param replace: If True, replaces the contents of the file if it |
| 396 already exists. |
| 397 |
| 398 :type cb: function |
| 399 :param cb: (optional) a callback function that will be called to report |
| 400 progress on the download. The callback should accept two integer |
| 401 parameters, the first representing the number of bytes that have |
| 402 been successfully transmitted from GS and the second representing |
| 403 the total number of bytes that need to be transmitted. |
| 404 |
| 405 :type cb: int |
| 406 :param num_cb: (optional) If a callback is specified with the cb |
| 407 parameter this parameter determines the granularity of the callback |
| 408 by defining the maximum number of times the callback will be called |
| 409 during the file transfer. |
| 410 |
| 411 :type policy: :class:`boto.gs.acl.CannedACLStrings` |
| 412 :param policy: A canned ACL policy that will be applied to the new key |
| 413 in GS. |
| 414 |
| 415 :type md5: A tuple containing the hexdigest version of the MD5 checksum |
| 416 of the file as the first element and the Base64-encoded version of |
| 417 the plain checksum as the second element. This is the same format |
| 418 returned by the compute_md5 method. |
| 419 :param md5: If you need to compute the MD5 for any reason prior to |
| 420 upload, it's silly to have to do it twice so this param, if present, |
| 421 will be used as the MD5 values of the file. Otherwise, the checksum |
| 422 will be computed. |
| 423 |
| 424 :type res_upload_handler: ResumableUploadHandler |
| 425 :param res_upload_handler: If provided, this handler will perform the |
| 426 upload. |
| 427 |
| 428 :type if_generation: int |
| 429 :param if_generation: (optional) If set to a generation number, the |
| 430 object will only be written to if its current generation number is |
| 431 this value. If set to the value 0, the object will only be written |
| 432 if it doesn't already exist. |
| 433 """ |
| 434 # Clear out any previously computed md5 hashes, since we are setting the
content. |
| 435 self.md5 = None |
| 436 self.base64md5 = None |
| 437 |
| 438 fp = open(filename, 'rb') |
| 439 self.set_contents_from_file(fp, headers, replace, cb, num_cb, |
| 440 policy, md5, res_upload_handler, |
| 441 if_generation=if_generation) |
| 442 fp.close() |
| 443 |
| 444 def set_contents_from_string(self, s, headers=None, replace=True, |
| 445 cb=None, num_cb=10, policy=None, md5=None, |
| 446 if_generation=None): |
| 447 """ |
| 448 Store an object in S3 using the name of the Key object as the |
| 449 key in S3 and the string 's' as the contents. |
| 450 See set_contents_from_file method for details about the |
| 451 parameters. |
| 452 |
| 453 :type headers: dict |
| 454 :param headers: Additional headers to pass along with the |
| 455 request to AWS. |
| 456 |
| 457 :type replace: bool |
| 458 :param replace: If True, replaces the contents of the file if |
| 459 it already exists. |
| 460 |
| 461 :type cb: function |
| 462 :param cb: a callback function that will be called to report |
| 463 progress on the upload. The callback should accept |
| 464 two integer parameters, the first representing the |
| 465 number of bytes that have been successfully |
| 466 transmitted to S3 and the second representing the |
| 467 size of the to be transmitted object. |
| 468 |
| 469 :type cb: int |
| 470 :param num_cb: (optional) If a callback is specified with |
| 471 the cb parameter this parameter determines the |
| 472 granularity of the callback by defining |
| 473 the maximum number of times the callback will |
| 474 be called during the file transfer. |
| 475 |
| 476 :type policy: :class:`boto.s3.acl.CannedACLStrings` |
| 477 :param policy: A canned ACL policy that will be applied to the |
| 478 new key in S3. |
| 479 |
| 480 :type md5: A tuple containing the hexdigest version of the MD5 |
| 481 checksum of the file as the first element and the |
| 482 Base64-encoded version of the plain checksum as the |
| 483 second element. This is the same format returned by |
| 484 the compute_md5 method. |
| 485 :param md5: If you need to compute the MD5 for any reason prior |
| 486 to upload, it's silly to have to do it twice so this |
| 487 param, if present, will be used as the MD5 values |
| 488 of the file. Otherwise, the checksum will be computed. |
| 489 |
| 490 :type if_generation: int |
| 491 :param if_generation: (optional) If set to a generation number, the |
| 492 object will only be written to if its current generation number is |
| 493 this value. If set to the value 0, the object will only be written |
| 494 if it doesn't already exist. |
| 495 """ |
| 496 |
| 497 # Clear out any previously computed md5 hashes, since we are setting the
content. |
| 498 self.md5 = None |
| 499 self.base64md5 = None |
| 500 |
| 501 if isinstance(s, unicode): |
| 502 s = s.encode("utf-8") |
| 503 fp = StringIO.StringIO(s) |
| 504 r = self.set_contents_from_file(fp, headers, replace, cb, num_cb, |
| 505 policy, md5, |
| 506 if_generation=if_generation) |
| 507 fp.close() |
| 508 return r |
| 509 |
| 510 def set_contents_from_stream(self, *args, **kwargs): |
| 511 """ |
| 512 Store an object using the name of the Key object as the key in |
| 513 cloud and the contents of the data stream pointed to by 'fp' as |
| 514 the contents. |
| 515 |
| 516 The stream object is not seekable and total size is not known. |
| 517 This has the implication that we can't specify the |
| 518 Content-Size and Content-MD5 in the header. So for huge |
| 519 uploads, the delay in calculating MD5 is avoided but with a |
| 520 penalty of inability to verify the integrity of the uploaded |
| 521 data. |
| 522 |
| 523 :type fp: file |
| 524 :param fp: the file whose contents are to be uploaded |
| 525 |
| 526 :type headers: dict |
| 527 :param headers: additional HTTP headers to be sent with the |
| 528 PUT request. |
| 529 |
| 530 :type replace: bool |
| 531 :param replace: If this parameter is False, the method will first check |
| 532 to see if an object exists in the bucket with the same key. If it |
| 533 does, it won't overwrite it. The default value is True which will |
| 534 overwrite the object. |
| 535 |
| 536 :type cb: function |
| 537 :param cb: a callback function that will be called to report |
| 538 progress on the upload. The callback should accept two integer |
| 539 parameters, the first representing the number of bytes that have |
| 540 been successfully transmitted to GS and the second representing the |
| 541 total number of bytes that need to be transmitted. |
| 542 |
| 543 :type num_cb: int |
| 544 :param num_cb: (optional) If a callback is specified with the |
| 545 cb parameter, this parameter determines the granularity of |
| 546 the callback by defining the maximum number of times the |
| 547 callback will be called during the file transfer. |
| 548 |
| 549 :type policy: :class:`boto.gs.acl.CannedACLStrings` |
| 550 :param policy: A canned ACL policy that will be applied to the new key |
| 551 in GS. |
| 552 |
| 553 :type reduced_redundancy: bool |
| 554 :param reduced_redundancy: If True, this will set the storage |
| 555 class of the new Key to be REDUCED_REDUNDANCY. The Reduced |
| 556 Redundancy Storage (RRS) feature of S3, provides lower |
| 557 redundancy at lower storage cost. |
| 558 |
| 559 :type size: int |
| 560 :param size: (optional) The Maximum number of bytes to read from |
| 561 the file pointer (fp). This is useful when uploading a |
| 562 file in multiple parts where you are splitting the file up |
| 563 into different ranges to be uploaded. If not specified, |
| 564 the default behaviour is to read all bytes from the file |
| 565 pointer. Less bytes may be available. |
| 566 |
| 567 :type if_generation: int |
| 568 :param if_generation: (optional) If set to a generation number, the |
| 569 object will only be written to if its current generation number is |
| 570 this value. If set to the value 0, the object will only be written |
| 571 if it doesn't already exist. |
| 572 """ |
| 573 if_generation = kwargs.pop('if_generation', None) |
| 574 if if_generation is not None: |
| 575 headers = kwargs.get('headers', {}) |
| 576 headers['x-goog-if-generation-match'] = str(if_generation) |
| 577 kwargs['headers'] = headers |
| 578 super(Key, self).set_contents_from_stream(*args, **kwargs) |
| 579 |
| 580 def set_acl(self, acl_or_str, headers=None, generation=None, |
| 581 if_generation=None, if_metageneration=None): |
| 582 """Sets the ACL for this object. |
| 583 |
| 584 :type acl_or_str: string or :class:`boto.gs.acl.ACL` |
| 585 :param acl_or_str: A canned ACL string (see |
| 586 :data:`~.gs.acl.CannedACLStrings`) or an ACL object. |
| 587 |
| 588 :type headers: dict |
| 589 :param headers: Additional headers to set during the request. |
| 590 |
| 591 :type generation: int |
| 592 :param generation: If specified, sets the ACL for a specific generation |
| 593 of a versioned object. If not specified, the current version is |
| 594 modified. |
| 595 |
| 596 :type if_generation: int |
| 597 :param if_generation: (optional) If set to a generation number, the acl |
| 598 will only be updated if its current generation number is this value. |
| 599 |
| 600 :type if_metageneration: int |
| 601 :param if_metageneration: (optional) If set to a metageneration number, |
| 602 the acl will only be updated if its current metageneration number is |
| 603 this value. |
| 604 """ |
| 605 if self.bucket != None: |
| 606 self.bucket.set_acl(acl_or_str, self.name, headers=headers, |
| 607 generation=generation, |
| 608 if_generation=if_generation, |
| 609 if_metageneration=if_metageneration) |
| 610 |
| 611 def get_acl(self, headers=None, generation=None): |
| 612 """Returns the ACL of this object. |
| 613 |
| 614 :param dict headers: Additional headers to set during the request. |
| 615 |
| 616 :param int generation: If specified, gets the ACL for a specific |
| 617 generation of a versioned object. If not specified, the current |
| 618 version is returned. |
| 619 |
| 620 :rtype: :class:`.gs.acl.ACL` |
| 621 """ |
| 622 if self.bucket != None: |
| 623 return self.bucket.get_acl(self.name, headers=headers, |
| 624 generation=generation) |
| 625 |
| 626 def get_xml_acl(self, headers=None, generation=None): |
| 627 """Returns the ACL string of this object. |
| 628 |
| 629 :param dict headers: Additional headers to set during the request. |
| 630 |
| 631 :param int generation: If specified, gets the ACL for a specific |
| 632 generation of a versioned object. If not specified, the current |
| 633 version is returned. |
| 634 |
| 635 :rtype: str |
| 636 """ |
| 637 if self.bucket != None: |
| 638 return self.bucket.get_xml_acl(self.name, headers=headers, |
| 639 generation=generation) |
| 640 |
| 641 def set_xml_acl(self, acl_str, headers=None, generation=None, |
| 642 if_generation=None, if_metageneration=None): |
| 643 """Sets this objects's ACL to an XML string. |
| 644 |
| 645 :type acl_str: string |
| 646 :param acl_str: A string containing the ACL XML. |
| 647 |
| 648 :type headers: dict |
| 649 :param headers: Additional headers to set during the request. |
| 650 |
| 651 :type generation: int |
| 652 :param generation: If specified, sets the ACL for a specific generation |
| 653 of a versioned object. If not specified, the current version is |
| 654 modified. |
| 655 |
| 656 :type if_generation: int |
| 657 :param if_generation: (optional) If set to a generation number, the acl |
| 658 will only be updated if its current generation number is this value. |
| 659 |
| 660 :type if_metageneration: int |
| 661 :param if_metageneration: (optional) If set to a metageneration number, |
| 662 the acl will only be updated if its current metageneration number is |
| 663 this value. |
| 664 """ |
| 665 if self.bucket != None: |
| 666 return self.bucket.set_xml_acl(acl_str, self.name, headers=headers, |
| 667 generation=generation, |
| 668 if_generation=if_generation, |
| 669 if_metageneration=if_metageneration) |
| 670 |
| 671 def set_canned_acl(self, acl_str, headers=None, generation=None, |
| 672 if_generation=None, if_metageneration=None): |
| 673 """Sets this objects's ACL using a predefined (canned) value. |
| 674 |
| 675 :type acl_str: string |
| 676 :param acl_str: A canned ACL string. See |
| 677 :data:`~.gs.acl.CannedACLStrings`. |
| 678 |
| 679 :type headers: dict |
| 680 :param headers: Additional headers to set during the request. |
| 681 |
| 682 :type generation: int |
| 683 :param generation: If specified, sets the ACL for a specific generation |
| 684 of a versioned object. If not specified, the current version is |
| 685 modified. |
| 686 |
| 687 :type if_generation: int |
| 688 :param if_generation: (optional) If set to a generation number, the acl |
| 689 will only be updated if its current generation number is this value. |
| 690 |
| 691 :type if_metageneration: int |
| 692 :param if_metageneration: (optional) If set to a metageneration number, |
| 693 the acl will only be updated if its current metageneration number is |
| 694 this value. |
| 695 """ |
| 696 if self.bucket != None: |
| 697 return self.bucket.set_canned_acl( |
| 698 acl_str, |
| 699 self.name, |
| 700 headers=headers, |
| 701 generation=generation, |
| 702 if_generation=if_generation, |
| 703 if_metageneration=if_metageneration |
| 704 ) |
OLD | NEW |