| OLD | NEW |
| 1 # Copyright 2010 Google Inc. | 1 # Copyright 2010 Google Inc. |
| 2 # | 2 # |
| 3 # Permission is hereby granted, free of charge, to any person obtaining a | 3 # Permission is hereby granted, free of charge, to any person obtaining a |
| 4 # copy of this software and associated documentation files (the | 4 # copy of this software and associated documentation files (the |
| 5 # "Software"), to deal in the Software without restriction, including | 5 # "Software"), to deal in the Software without restriction, including |
| 6 # without limitation the rights to use, copy, modify, merge, publish, dis- | 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 | 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- | 8 # persons to whom the Software is furnished to do so, subject to the fol- |
| 9 # lowing conditions: | 9 # lowing conditions: |
| 10 # | 10 # |
| 11 # The above copyright notice and this permission notice shall be included | 11 # The above copyright notice and this permission notice shall be included |
| 12 # in all copies or substantial portions of the Software. | 12 # in all copies or substantial portions of the Software. |
| 13 # | 13 # |
| 14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | 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- | 15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
| 16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | 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, | 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, | 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 | 19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 20 # IN THE SOFTWARE. | 20 # IN THE SOFTWARE. |
| 21 | 21 |
| 22 import StringIO |
| 22 from boto.s3.key import Key as S3Key | 23 from boto.s3.key import Key as S3Key |
| 23 | 24 |
| 24 class Key(S3Key): | 25 class Key(S3Key): |
| 25 | 26 |
| 26 def add_email_grant(self, permission, email_address): | 27 def add_email_grant(self, permission, email_address): |
| 27 """ | 28 """ |
| 28 Convenience method that provides a quick way to add an email grant to a | 29 Convenience method that provides a quick way to add an email grant to a |
| 29 key. This method retrieves the current ACL, creates a new grant based on | 30 key. This method retrieves the current ACL, creates a new grant based on |
| 30 the parameters passed in, adds that grant to the ACL and then PUT's the | 31 the parameters passed in, adds that grant to the ACL and then PUT's the |
| 31 new ACL back to GS. | 32 new ACL back to GS. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 for more details on permissions. | 101 for more details on permissions. |
| 101 | 102 |
| 102 :type group_id: string | 103 :type group_id: string |
| 103 :param group_id: The canonical group id associated with the Google | 104 :param group_id: The canonical group id associated with the Google |
| 104 Groups account you are granting the permission to. | 105 Groups account you are granting the permission to. |
| 105 """ | 106 """ |
| 106 acl = self.get_acl() | 107 acl = self.get_acl() |
| 107 acl.add_group_grant(permission, group_id) | 108 acl.add_group_grant(permission, group_id) |
| 108 self.set_acl(acl) | 109 self.set_acl(acl) |
| 109 | 110 |
| 110 def set_contents_from_file(self, fp, headers={}, replace=True, | 111 def set_contents_from_file(self, fp, headers=None, replace=True, |
| 111 cb=None, num_cb=10, policy=None, md5=None, | 112 cb=None, num_cb=10, policy=None, md5=None, |
| 112 res_upload_handler=None): | 113 res_upload_handler=None): |
| 113 """ | 114 """ |
| 114 Store an object in GS using the name of the Key object as the | 115 Store an object in GS using the name of the Key object as the |
| 115 key in GS and the contents of the file pointed to by 'fp' as the | 116 key in GS and the contents of the file pointed to by 'fp' as the |
| 116 contents. | 117 contents. |
| 117 | 118 |
| 118 :type fp: file | 119 :type fp: file |
| 119 :param fp: the file whose contents are to be uploaded | 120 :param fp: the file whose contents are to be uploaded |
| 120 | 121 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 :type res_upload_handler: ResumableUploadHandler | 157 :type res_upload_handler: ResumableUploadHandler |
| 157 :param res_upload_handler: If provided, this handler will perform the | 158 :param res_upload_handler: If provided, this handler will perform the |
| 158 upload. | 159 upload. |
| 159 | 160 |
| 160 TODO: At some point we should refactor the Bucket and Key classes, | 161 TODO: At some point we should refactor the Bucket and Key classes, |
| 161 to move functionality common to all providers into a parent class, | 162 to move functionality common to all providers into a parent class, |
| 162 and provider-specific functionality into subclasses (rather than | 163 and provider-specific functionality into subclasses (rather than |
| 163 just overriding/sharing code the way it currently works). | 164 just overriding/sharing code the way it currently works). |
| 164 """ | 165 """ |
| 165 provider = self.bucket.connection.provider | 166 provider = self.bucket.connection.provider |
| 166 if headers is None: | 167 headers = headers or {} |
| 167 headers = {} | |
| 168 if policy: | 168 if policy: |
| 169 headers[provider.acl_header] = policy | 169 headers[provider.acl_header] = policy |
| 170 if hasattr(fp, 'name'): | 170 if hasattr(fp, 'name'): |
| 171 self.path = fp.name | 171 self.path = fp.name |
| 172 if self.bucket != None: | 172 if self.bucket != None: |
| 173 if not md5: | 173 if not md5: |
| 174 md5 = self.compute_md5(fp) | 174 md5 = self.compute_md5(fp) |
| 175 else: | 175 else: |
| 176 # Even if md5 is provided, still need to set size of content. | 176 # Even if md5 is provided, still need to set size of content. |
| 177 fp.seek(0, 2) | 177 fp.seek(0, 2) |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 will be computed. | 238 will be computed. |
| 239 | 239 |
| 240 :type res_upload_handler: ResumableUploadHandler | 240 :type res_upload_handler: ResumableUploadHandler |
| 241 :param res_upload_handler: If provided, this handler will perform the | 241 :param res_upload_handler: If provided, this handler will perform the |
| 242 upload. | 242 upload. |
| 243 """ | 243 """ |
| 244 fp = open(filename, 'rb') | 244 fp = open(filename, 'rb') |
| 245 self.set_contents_from_file(fp, headers, replace, cb, num_cb, | 245 self.set_contents_from_file(fp, headers, replace, cb, num_cb, |
| 246 policy, md5, res_upload_handler) | 246 policy, md5, res_upload_handler) |
| 247 fp.close() | 247 fp.close() |
| 248 |
| 249 def set_contents_from_string(self, s, headers=None, replace=True, |
| 250 cb=None, num_cb=10, policy=None, md5=None): |
| 251 """ |
| 252 Store an object in S3 using the name of the Key object as the |
| 253 key in S3 and the string 's' as the contents. |
| 254 See set_contents_from_file method for details about the |
| 255 parameters. |
| 256 |
| 257 :type headers: dict |
| 258 :param headers: Additional headers to pass along with the |
| 259 request to AWS. |
| 260 |
| 261 :type replace: bool |
| 262 :param replace: If True, replaces the contents of the file if |
| 263 it already exists. |
| 264 |
| 265 :type cb: function |
| 266 :param cb: a callback function that will be called to report |
| 267 progress on the upload. The callback should accept |
| 268 two integer parameters, the first representing the |
| 269 number of bytes that have been successfully |
| 270 transmitted to S3 and the second representing the |
| 271 size of the to be transmitted object. |
| 272 |
| 273 :type cb: int |
| 274 :param num_cb: (optional) If a callback is specified with |
| 275 the cb parameter this parameter determines the |
| 276 granularity of the callback by defining |
| 277 the maximum number of times the callback will |
| 278 be called during the file transfer. |
| 279 |
| 280 :type policy: :class:`boto.s3.acl.CannedACLStrings` |
| 281 :param policy: A canned ACL policy that will be applied to the |
| 282 new key in S3. |
| 283 |
| 284 :type md5: A tuple containing the hexdigest version of the MD5 |
| 285 checksum of the file as the first element and the |
| 286 Base64-encoded version of the plain checksum as the |
| 287 second element. This is the same format returned by |
| 288 the compute_md5 method. |
| 289 :param md5: If you need to compute the MD5 for any reason prior |
| 290 to upload, it's silly to have to do it twice so this |
| 291 param, if present, will be used as the MD5 values |
| 292 of the file. Otherwise, the checksum will be computed. |
| 293 """ |
| 294 if isinstance(s, unicode): |
| 295 s = s.encode("utf-8") |
| 296 fp = StringIO.StringIO(s) |
| 297 r = self.set_contents_from_file(fp, headers, replace, cb, num_cb, |
| 298 policy, md5) |
| 299 fp.close() |
| 300 return r |
| OLD | NEW |