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 |