gcloud 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (768) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +4 -0
  3. data/Makefile +4 -0
  4. data/Manifest +760 -1
  5. data/bin/gcloud +7 -0
  6. data/bin/{gcutil → gcutil.symlink} +0 -0
  7. data/bin/gsutil-symlink +377 -0
  8. data/gcloud.gemspec +5 -5
  9. data/packages/gsutil/CHECKSUM +1 -0
  10. data/packages/gsutil/COPYING +202 -0
  11. data/packages/gsutil/LICENSE.third_party +295 -0
  12. data/packages/gsutil/MANIFEST.in +5 -0
  13. data/packages/gsutil/README +38 -0
  14. data/packages/gsutil/README.pkg +49 -0
  15. data/packages/gsutil/ReleaseNotes.txt +780 -0
  16. data/packages/gsutil/VERSION +1 -0
  17. data/packages/gsutil/boto/Changelog.rst +35 -0
  18. data/packages/gsutil/boto/LICENSE +18 -0
  19. data/packages/gsutil/boto/MANIFEST.in +12 -0
  20. data/packages/gsutil/boto/README.rst +163 -0
  21. data/packages/gsutil/boto/bin/asadmin +290 -0
  22. data/packages/gsutil/boto/bin/bundle_image +27 -0
  23. data/packages/gsutil/boto/bin/cfadmin +108 -0
  24. data/packages/gsutil/boto/bin/cq +89 -0
  25. data/packages/gsutil/boto/bin/cwutil +140 -0
  26. data/packages/gsutil/boto/bin/elbadmin +284 -0
  27. data/packages/gsutil/boto/bin/fetch_file +43 -0
  28. data/packages/gsutil/boto/bin/glacier +154 -0
  29. data/packages/gsutil/boto/bin/instance_events +145 -0
  30. data/packages/gsutil/boto/bin/kill_instance +35 -0
  31. data/packages/gsutil/boto/bin/launch_instance +252 -0
  32. data/packages/gsutil/boto/bin/list_instances +90 -0
  33. data/packages/gsutil/boto/bin/lss3 +77 -0
  34. data/packages/gsutil/boto/bin/mturk +465 -0
  35. data/packages/gsutil/boto/bin/pyami_sendmail +52 -0
  36. data/packages/gsutil/boto/bin/route53 +205 -0
  37. data/packages/gsutil/boto/bin/s3put +374 -0
  38. data/packages/gsutil/boto/bin/sdbadmin +194 -0
  39. data/packages/gsutil/boto/bin/taskadmin +116 -0
  40. data/packages/gsutil/boto/boto/__init__.py +793 -0
  41. data/packages/gsutil/boto/boto/__init__.pyc +0 -0
  42. data/packages/gsutil/boto/boto/auth.py +682 -0
  43. data/packages/gsutil/boto/boto/auth.pyc +0 -0
  44. data/packages/gsutil/boto/boto/auth_handler.py +58 -0
  45. data/packages/gsutil/boto/boto/auth_handler.pyc +0 -0
  46. data/packages/gsutil/boto/boto/beanstalk/__init__.py +65 -0
  47. data/packages/gsutil/boto/boto/beanstalk/exception.py +64 -0
  48. data/packages/gsutil/boto/boto/beanstalk/layer1.py +1153 -0
  49. data/packages/gsutil/boto/boto/beanstalk/response.py +703 -0
  50. data/packages/gsutil/boto/boto/beanstalk/wrapper.py +29 -0
  51. data/packages/gsutil/boto/boto/cacerts/__init__.py +22 -0
  52. data/packages/gsutil/boto/boto/cacerts/__init__.pyc +0 -0
  53. data/packages/gsutil/boto/boto/cacerts/cacerts.txt +633 -0
  54. data/packages/gsutil/boto/boto/cloudformation/__init__.py +68 -0
  55. data/packages/gsutil/boto/boto/cloudformation/connection.py +364 -0
  56. data/packages/gsutil/boto/boto/cloudformation/stack.py +360 -0
  57. data/packages/gsutil/boto/boto/cloudformation/template.py +43 -0
  58. data/packages/gsutil/boto/boto/cloudfront/__init__.py +324 -0
  59. data/packages/gsutil/boto/boto/cloudfront/distribution.py +745 -0
  60. data/packages/gsutil/boto/boto/cloudfront/exception.py +26 -0
  61. data/packages/gsutil/boto/boto/cloudfront/identity.py +122 -0
  62. data/packages/gsutil/boto/boto/cloudfront/invalidation.py +216 -0
  63. data/packages/gsutil/boto/boto/cloudfront/logging.py +38 -0
  64. data/packages/gsutil/boto/boto/cloudfront/object.py +48 -0
  65. data/packages/gsutil/boto/boto/cloudfront/origin.py +150 -0
  66. data/packages/gsutil/boto/boto/cloudfront/signers.py +60 -0
  67. data/packages/gsutil/boto/boto/cloudsearch/__init__.py +45 -0
  68. data/packages/gsutil/boto/boto/cloudsearch/document.py +265 -0
  69. data/packages/gsutil/boto/boto/cloudsearch/domain.py +394 -0
  70. data/packages/gsutil/boto/boto/cloudsearch/layer1.py +738 -0
  71. data/packages/gsutil/boto/boto/cloudsearch/layer2.py +67 -0
  72. data/packages/gsutil/boto/boto/cloudsearch/optionstatus.py +248 -0
  73. data/packages/gsutil/boto/boto/cloudsearch/search.py +365 -0
  74. data/packages/gsutil/boto/boto/cloudsearch/sourceattribute.py +75 -0
  75. data/packages/gsutil/boto/boto/compat.py +28 -0
  76. data/packages/gsutil/boto/boto/compat.pyc +0 -0
  77. data/packages/gsutil/boto/boto/connection.py +1081 -0
  78. data/packages/gsutil/boto/boto/connection.pyc +0 -0
  79. data/packages/gsutil/boto/boto/contrib/__init__.py +22 -0
  80. data/packages/gsutil/boto/boto/contrib/ymlmessage.py +52 -0
  81. data/packages/gsutil/boto/boto/core/README +58 -0
  82. data/packages/gsutil/boto/boto/core/__init__.py +23 -0
  83. data/packages/gsutil/boto/boto/core/auth.py +78 -0
  84. data/packages/gsutil/boto/boto/core/credentials.py +154 -0
  85. data/packages/gsutil/boto/boto/core/dictresponse.py +178 -0
  86. data/packages/gsutil/boto/boto/core/service.py +67 -0
  87. data/packages/gsutil/boto/boto/datapipeline/__init__.py +0 -0
  88. data/packages/gsutil/boto/boto/datapipeline/exceptions.py +42 -0
  89. data/packages/gsutil/boto/boto/datapipeline/layer1.py +546 -0
  90. data/packages/gsutil/boto/boto/dynamodb/__init__.py +66 -0
  91. data/packages/gsutil/boto/boto/dynamodb/batch.py +262 -0
  92. data/packages/gsutil/boto/boto/dynamodb/condition.py +170 -0
  93. data/packages/gsutil/boto/boto/dynamodb/exceptions.py +64 -0
  94. data/packages/gsutil/boto/boto/dynamodb/item.py +196 -0
  95. data/packages/gsutil/boto/boto/dynamodb/layer1.py +575 -0
  96. data/packages/gsutil/boto/boto/dynamodb/layer2.py +798 -0
  97. data/packages/gsutil/boto/boto/dynamodb/schema.py +112 -0
  98. data/packages/gsutil/boto/boto/dynamodb/table.py +540 -0
  99. data/packages/gsutil/boto/boto/dynamodb/types.py +326 -0
  100. data/packages/gsutil/boto/boto/ec2/__init__.py +96 -0
  101. data/packages/gsutil/boto/boto/ec2/address.py +103 -0
  102. data/packages/gsutil/boto/boto/ec2/autoscale/__init__.py +781 -0
  103. data/packages/gsutil/boto/boto/ec2/autoscale/activity.py +74 -0
  104. data/packages/gsutil/boto/boto/ec2/autoscale/group.py +337 -0
  105. data/packages/gsutil/boto/boto/ec2/autoscale/instance.py +60 -0
  106. data/packages/gsutil/boto/boto/ec2/autoscale/launchconfig.py +209 -0
  107. data/packages/gsutil/boto/boto/ec2/autoscale/policy.py +166 -0
  108. data/packages/gsutil/boto/boto/ec2/autoscale/request.py +38 -0
  109. data/packages/gsutil/boto/boto/ec2/autoscale/scheduled.py +60 -0
  110. data/packages/gsutil/boto/boto/ec2/autoscale/tag.py +84 -0
  111. data/packages/gsutil/boto/boto/ec2/blockdevicemapping.py +141 -0
  112. data/packages/gsutil/boto/boto/ec2/bundleinstance.py +78 -0
  113. data/packages/gsutil/boto/boto/ec2/buyreservation.py +84 -0
  114. data/packages/gsutil/boto/boto/ec2/cloudwatch/__init__.py +603 -0
  115. data/packages/gsutil/boto/boto/ec2/cloudwatch/alarm.py +316 -0
  116. data/packages/gsutil/boto/boto/ec2/cloudwatch/datapoint.py +40 -0
  117. data/packages/gsutil/boto/boto/ec2/cloudwatch/dimension.py +38 -0
  118. data/packages/gsutil/boto/boto/ec2/cloudwatch/listelement.py +31 -0
  119. data/packages/gsutil/boto/boto/ec2/cloudwatch/metric.py +175 -0
  120. data/packages/gsutil/boto/boto/ec2/connection.py +3409 -0
  121. data/packages/gsutil/boto/boto/ec2/ec2object.py +107 -0
  122. data/packages/gsutil/boto/boto/ec2/elb/__init__.py +553 -0
  123. data/packages/gsutil/boto/boto/ec2/elb/healthcheck.py +89 -0
  124. data/packages/gsutil/boto/boto/ec2/elb/instancestate.py +62 -0
  125. data/packages/gsutil/boto/boto/ec2/elb/listelement.py +36 -0
  126. data/packages/gsutil/boto/boto/ec2/elb/listener.py +75 -0
  127. data/packages/gsutil/boto/boto/ec2/elb/loadbalancer.py +324 -0
  128. data/packages/gsutil/boto/boto/ec2/elb/policies.py +89 -0
  129. data/packages/gsutil/boto/boto/ec2/elb/securitygroup.py +38 -0
  130. data/packages/gsutil/boto/boto/ec2/group.py +39 -0
  131. data/packages/gsutil/boto/boto/ec2/image.py +350 -0
  132. data/packages/gsutil/boto/boto/ec2/instance.py +661 -0
  133. data/packages/gsutil/boto/boto/ec2/instanceinfo.py +51 -0
  134. data/packages/gsutil/boto/boto/ec2/instancestatus.py +207 -0
  135. data/packages/gsutil/boto/boto/ec2/keypair.py +113 -0
  136. data/packages/gsutil/boto/boto/ec2/launchspecification.py +105 -0
  137. data/packages/gsutil/boto/boto/ec2/networkinterface.py +247 -0
  138. data/packages/gsutil/boto/boto/ec2/placementgroup.py +51 -0
  139. data/packages/gsutil/boto/boto/ec2/regioninfo.py +34 -0
  140. data/packages/gsutil/boto/boto/ec2/reservedinstance.py +227 -0
  141. data/packages/gsutil/boto/boto/ec2/securitygroup.py +357 -0
  142. data/packages/gsutil/boto/boto/ec2/snapshot.py +170 -0
  143. data/packages/gsutil/boto/boto/ec2/spotdatafeedsubscription.py +63 -0
  144. data/packages/gsutil/boto/boto/ec2/spotinstancerequest.py +188 -0
  145. data/packages/gsutil/boto/boto/ec2/spotpricehistory.py +55 -0
  146. data/packages/gsutil/boto/boto/ec2/tag.py +87 -0
  147. data/packages/gsutil/boto/boto/ec2/vmtype.py +58 -0
  148. data/packages/gsutil/boto/boto/ec2/volume.py +293 -0
  149. data/packages/gsutil/boto/boto/ec2/volumestatus.py +200 -0
  150. data/packages/gsutil/boto/boto/ec2/zone.py +80 -0
  151. data/packages/gsutil/boto/boto/ecs/__init__.py +90 -0
  152. data/packages/gsutil/boto/boto/ecs/item.py +153 -0
  153. data/packages/gsutil/boto/boto/elasticache/__init__.py +62 -0
  154. data/packages/gsutil/boto/boto/elasticache/layer1.py +1252 -0
  155. data/packages/gsutil/boto/boto/elastictranscoder/__init__.py +62 -0
  156. data/packages/gsutil/boto/boto/elastictranscoder/exceptions.py +46 -0
  157. data/packages/gsutil/boto/boto/elastictranscoder/layer1.py +509 -0
  158. data/packages/gsutil/boto/boto/emr/__init__.py +73 -0
  159. data/packages/gsutil/boto/boto/emr/bootstrap_action.py +44 -0
  160. data/packages/gsutil/boto/boto/emr/connection.py +531 -0
  161. data/packages/gsutil/boto/boto/emr/emrobject.py +176 -0
  162. data/packages/gsutil/boto/boto/emr/instance_group.py +43 -0
  163. data/packages/gsutil/boto/boto/emr/step.py +281 -0
  164. data/packages/gsutil/boto/boto/exception.py +476 -0
  165. data/packages/gsutil/boto/boto/exception.pyc +0 -0
  166. data/packages/gsutil/boto/boto/file/README +49 -0
  167. data/packages/gsutil/boto/boto/file/__init__.py +28 -0
  168. data/packages/gsutil/boto/boto/file/bucket.py +112 -0
  169. data/packages/gsutil/boto/boto/file/connection.py +33 -0
  170. data/packages/gsutil/boto/boto/file/key.py +199 -0
  171. data/packages/gsutil/boto/boto/file/simpleresultset.py +30 -0
  172. data/packages/gsutil/boto/boto/fps/__init__.py +21 -0
  173. data/packages/gsutil/boto/boto/fps/connection.py +369 -0
  174. data/packages/gsutil/boto/boto/fps/exception.py +344 -0
  175. data/packages/gsutil/boto/boto/fps/response.py +175 -0
  176. data/packages/gsutil/boto/boto/glacier/__init__.py +57 -0
  177. data/packages/gsutil/boto/boto/glacier/concurrent.py +409 -0
  178. data/packages/gsutil/boto/boto/glacier/exceptions.py +58 -0
  179. data/packages/gsutil/boto/boto/glacier/job.py +152 -0
  180. data/packages/gsutil/boto/boto/glacier/layer1.py +637 -0
  181. data/packages/gsutil/boto/boto/glacier/layer2.py +93 -0
  182. data/packages/gsutil/boto/boto/glacier/response.py +48 -0
  183. data/packages/gsutil/boto/boto/glacier/utils.py +163 -0
  184. data/packages/gsutil/boto/boto/glacier/vault.py +387 -0
  185. data/packages/gsutil/boto/boto/glacier/writer.py +242 -0
  186. data/packages/gsutil/boto/boto/gs/__init__.py +22 -0
  187. data/packages/gsutil/boto/boto/gs/__init__.pyc +0 -0
  188. data/packages/gsutil/boto/boto/gs/acl.py +304 -0
  189. data/packages/gsutil/boto/boto/gs/acl.pyc +0 -0
  190. data/packages/gsutil/boto/boto/gs/bucket.py +870 -0
  191. data/packages/gsutil/boto/boto/gs/bucket.pyc +0 -0
  192. data/packages/gsutil/boto/boto/gs/bucketlistresultset.py +64 -0
  193. data/packages/gsutil/boto/boto/gs/bucketlistresultset.pyc +0 -0
  194. data/packages/gsutil/boto/boto/gs/connection.py +103 -0
  195. data/packages/gsutil/boto/boto/gs/connection.pyc +0 -0
  196. data/packages/gsutil/boto/boto/gs/cors.py +169 -0
  197. data/packages/gsutil/boto/boto/gs/cors.pyc +0 -0
  198. data/packages/gsutil/boto/boto/gs/key.py +704 -0
  199. data/packages/gsutil/boto/boto/gs/key.pyc +0 -0
  200. data/packages/gsutil/boto/boto/gs/resumable_upload_handler.py +659 -0
  201. data/packages/gsutil/boto/boto/gs/resumable_upload_handler.pyc +0 -0
  202. data/packages/gsutil/boto/boto/gs/user.py +54 -0
  203. data/packages/gsutil/boto/boto/gs/user.pyc +0 -0
  204. data/packages/gsutil/boto/boto/handler.py +44 -0
  205. data/packages/gsutil/boto/boto/handler.pyc +0 -0
  206. data/packages/gsutil/boto/boto/https_connection.py +124 -0
  207. data/packages/gsutil/boto/boto/https_connection.pyc +0 -0
  208. data/packages/gsutil/boto/boto/iam/__init__.py +74 -0
  209. data/packages/gsutil/boto/boto/iam/connection.py +1317 -0
  210. data/packages/gsutil/boto/boto/iam/summarymap.py +42 -0
  211. data/packages/gsutil/boto/boto/jsonresponse.py +163 -0
  212. data/packages/gsutil/boto/boto/jsonresponse.pyc +0 -0
  213. data/packages/gsutil/boto/boto/manage/__init__.py +23 -0
  214. data/packages/gsutil/boto/boto/manage/cmdshell.py +241 -0
  215. data/packages/gsutil/boto/boto/manage/propget.py +64 -0
  216. data/packages/gsutil/boto/boto/manage/server.py +556 -0
  217. data/packages/gsutil/boto/boto/manage/task.py +175 -0
  218. data/packages/gsutil/boto/boto/manage/test_manage.py +34 -0
  219. data/packages/gsutil/boto/boto/manage/volume.py +420 -0
  220. data/packages/gsutil/boto/boto/mashups/__init__.py +23 -0
  221. data/packages/gsutil/boto/boto/mashups/interactive.py +97 -0
  222. data/packages/gsutil/boto/boto/mashups/iobject.py +115 -0
  223. data/packages/gsutil/boto/boto/mashups/order.py +211 -0
  224. data/packages/gsutil/boto/boto/mashups/server.py +395 -0
  225. data/packages/gsutil/boto/boto/mturk/__init__.py +23 -0
  226. data/packages/gsutil/boto/boto/mturk/connection.py +1027 -0
  227. data/packages/gsutil/boto/boto/mturk/layoutparam.py +55 -0
  228. data/packages/gsutil/boto/boto/mturk/notification.py +103 -0
  229. data/packages/gsutil/boto/boto/mturk/price.py +48 -0
  230. data/packages/gsutil/boto/boto/mturk/qualification.py +137 -0
  231. data/packages/gsutil/boto/boto/mturk/question.py +455 -0
  232. data/packages/gsutil/boto/boto/mws/__init__.py +21 -0
  233. data/packages/gsutil/boto/boto/mws/connection.py +813 -0
  234. data/packages/gsutil/boto/boto/mws/exception.py +75 -0
  235. data/packages/gsutil/boto/boto/mws/response.py +655 -0
  236. data/packages/gsutil/boto/boto/plugin.py +90 -0
  237. data/packages/gsutil/boto/boto/plugin.pyc +0 -0
  238. data/packages/gsutil/boto/boto/provider.py +337 -0
  239. data/packages/gsutil/boto/boto/provider.pyc +0 -0
  240. data/packages/gsutil/boto/boto/pyami/__init__.py +22 -0
  241. data/packages/gsutil/boto/boto/pyami/__init__.pyc +0 -0
  242. data/packages/gsutil/boto/boto/pyami/bootstrap.py +134 -0
  243. data/packages/gsutil/boto/boto/pyami/config.py +229 -0
  244. data/packages/gsutil/boto/boto/pyami/config.pyc +0 -0
  245. data/packages/gsutil/boto/boto/pyami/copybot.cfg +60 -0
  246. data/packages/gsutil/boto/boto/pyami/copybot.py +97 -0
  247. data/packages/gsutil/boto/boto/pyami/helloworld.py +28 -0
  248. data/packages/gsutil/boto/boto/pyami/installers/__init__.py +64 -0
  249. data/packages/gsutil/boto/boto/pyami/installers/ubuntu/__init__.py +22 -0
  250. data/packages/gsutil/boto/boto/pyami/installers/ubuntu/apache.py +43 -0
  251. data/packages/gsutil/boto/boto/pyami/installers/ubuntu/ebs.py +238 -0
  252. data/packages/gsutil/boto/boto/pyami/installers/ubuntu/installer.py +96 -0
  253. data/packages/gsutil/boto/boto/pyami/installers/ubuntu/mysql.py +109 -0
  254. data/packages/gsutil/boto/boto/pyami/installers/ubuntu/trac.py +139 -0
  255. data/packages/gsutil/boto/boto/pyami/launch_ami.py +178 -0
  256. data/packages/gsutil/boto/boto/pyami/scriptbase.py +44 -0
  257. data/packages/gsutil/boto/boto/pyami/startup.py +60 -0
  258. data/packages/gsutil/boto/boto/rds/__init__.py +1194 -0
  259. data/packages/gsutil/boto/boto/rds/dbinstance.py +357 -0
  260. data/packages/gsutil/boto/boto/rds/dbsecuritygroup.py +177 -0
  261. data/packages/gsutil/boto/boto/rds/dbsnapshot.py +108 -0
  262. data/packages/gsutil/boto/boto/rds/event.py +49 -0
  263. data/packages/gsutil/boto/boto/rds/parametergroup.py +201 -0
  264. data/packages/gsutil/boto/boto/rds/regioninfo.py +32 -0
  265. data/packages/gsutil/boto/boto/regioninfo.py +63 -0
  266. data/packages/gsutil/boto/boto/regioninfo.pyc +0 -0
  267. data/packages/gsutil/boto/boto/resultset.py +169 -0
  268. data/packages/gsutil/boto/boto/resultset.pyc +0 -0
  269. data/packages/gsutil/boto/boto/roboto/__init__.py +1 -0
  270. data/packages/gsutil/boto/boto/roboto/awsqueryrequest.py +504 -0
  271. data/packages/gsutil/boto/boto/roboto/awsqueryservice.py +121 -0
  272. data/packages/gsutil/boto/boto/roboto/param.py +147 -0
  273. data/packages/gsutil/boto/boto/route53/__init__.py +75 -0
  274. data/packages/gsutil/boto/boto/route53/connection.py +403 -0
  275. data/packages/gsutil/boto/boto/route53/exception.py +27 -0
  276. data/packages/gsutil/boto/boto/route53/hostedzone.py +56 -0
  277. data/packages/gsutil/boto/boto/route53/record.py +306 -0
  278. data/packages/gsutil/boto/boto/route53/status.py +42 -0
  279. data/packages/gsutil/boto/boto/route53/zone.py +412 -0
  280. data/packages/gsutil/boto/boto/s3/__init__.py +84 -0
  281. data/packages/gsutil/boto/boto/s3/__init__.pyc +0 -0
  282. data/packages/gsutil/boto/boto/s3/acl.py +164 -0
  283. data/packages/gsutil/boto/boto/s3/acl.pyc +0 -0
  284. data/packages/gsutil/boto/boto/s3/bucket.py +1634 -0
  285. data/packages/gsutil/boto/boto/s3/bucket.pyc +0 -0
  286. data/packages/gsutil/boto/boto/s3/bucketlistresultset.py +139 -0
  287. data/packages/gsutil/boto/boto/s3/bucketlistresultset.pyc +0 -0
  288. data/packages/gsutil/boto/boto/s3/bucketlogging.py +83 -0
  289. data/packages/gsutil/boto/boto/s3/bucketlogging.pyc +0 -0
  290. data/packages/gsutil/boto/boto/s3/connection.py +540 -0
  291. data/packages/gsutil/boto/boto/s3/connection.pyc +0 -0
  292. data/packages/gsutil/boto/boto/s3/cors.py +210 -0
  293. data/packages/gsutil/boto/boto/s3/cors.pyc +0 -0
  294. data/packages/gsutil/boto/boto/s3/deletemarker.py +55 -0
  295. data/packages/gsutil/boto/boto/s3/deletemarker.pyc +0 -0
  296. data/packages/gsutil/boto/boto/s3/key.py +1712 -0
  297. data/packages/gsutil/boto/boto/s3/key.pyc +0 -0
  298. data/packages/gsutil/boto/boto/s3/keyfile.py +134 -0
  299. data/packages/gsutil/boto/boto/s3/keyfile.pyc +0 -0
  300. data/packages/gsutil/boto/boto/s3/lifecycle.py +231 -0
  301. data/packages/gsutil/boto/boto/s3/lifecycle.pyc +0 -0
  302. data/packages/gsutil/boto/boto/s3/multidelete.py +138 -0
  303. data/packages/gsutil/boto/boto/s3/multidelete.pyc +0 -0
  304. data/packages/gsutil/boto/boto/s3/multipart.py +315 -0
  305. data/packages/gsutil/boto/boto/s3/multipart.pyc +0 -0
  306. data/packages/gsutil/boto/boto/s3/prefix.py +42 -0
  307. data/packages/gsutil/boto/boto/s3/prefix.pyc +0 -0
  308. data/packages/gsutil/boto/boto/s3/resumable_download_handler.py +339 -0
  309. data/packages/gsutil/boto/boto/s3/resumable_download_handler.pyc +0 -0
  310. data/packages/gsutil/boto/boto/s3/tagging.py +71 -0
  311. data/packages/gsutil/boto/boto/s3/tagging.pyc +0 -0
  312. data/packages/gsutil/boto/boto/s3/user.py +49 -0
  313. data/packages/gsutil/boto/boto/s3/user.pyc +0 -0
  314. data/packages/gsutil/boto/boto/s3/website.py +237 -0
  315. data/packages/gsutil/boto/boto/s3/website.pyc +0 -0
  316. data/packages/gsutil/boto/boto/sdb/__init__.py +67 -0
  317. data/packages/gsutil/boto/boto/sdb/connection.py +617 -0
  318. data/packages/gsutil/boto/boto/sdb/db/__init__.py +20 -0
  319. data/packages/gsutil/boto/boto/sdb/db/blob.py +75 -0
  320. data/packages/gsutil/boto/boto/sdb/db/key.py +59 -0
  321. data/packages/gsutil/boto/boto/sdb/db/manager/__init__.py +85 -0
  322. data/packages/gsutil/boto/boto/sdb/db/manager/sdbmanager.py +732 -0
  323. data/packages/gsutil/boto/boto/sdb/db/manager/xmlmanager.py +517 -0
  324. data/packages/gsutil/boto/boto/sdb/db/model.py +294 -0
  325. data/packages/gsutil/boto/boto/sdb/db/property.py +703 -0
  326. data/packages/gsutil/boto/boto/sdb/db/query.py +85 -0
  327. data/packages/gsutil/boto/boto/sdb/db/sequence.py +226 -0
  328. data/packages/gsutil/boto/boto/sdb/db/test_db.py +231 -0
  329. data/packages/gsutil/boto/boto/sdb/domain.py +377 -0
  330. data/packages/gsutil/boto/boto/sdb/item.py +181 -0
  331. data/packages/gsutil/boto/boto/sdb/queryresultset.py +92 -0
  332. data/packages/gsutil/boto/boto/sdb/regioninfo.py +32 -0
  333. data/packages/gsutil/boto/boto/services/__init__.py +23 -0
  334. data/packages/gsutil/boto/boto/services/bs.py +179 -0
  335. data/packages/gsutil/boto/boto/services/message.py +58 -0
  336. data/packages/gsutil/boto/boto/services/result.py +136 -0
  337. data/packages/gsutil/boto/boto/services/service.py +161 -0
  338. data/packages/gsutil/boto/boto/services/servicedef.py +91 -0
  339. data/packages/gsutil/boto/boto/services/sonofmmm.cfg +43 -0
  340. data/packages/gsutil/boto/boto/services/sonofmmm.py +81 -0
  341. data/packages/gsutil/boto/boto/services/submit.py +88 -0
  342. data/packages/gsutil/boto/boto/ses/__init__.py +54 -0
  343. data/packages/gsutil/boto/boto/ses/connection.py +521 -0
  344. data/packages/gsutil/boto/boto/ses/exceptions.py +77 -0
  345. data/packages/gsutil/boto/boto/sns/__init__.py +78 -0
  346. data/packages/gsutil/boto/boto/sns/connection.py +431 -0
  347. data/packages/gsutil/boto/boto/sqs/__init__.py +56 -0
  348. data/packages/gsutil/boto/boto/sqs/attributes.py +46 -0
  349. data/packages/gsutil/boto/boto/sqs/batchresults.py +95 -0
  350. data/packages/gsutil/boto/boto/sqs/connection.py +417 -0
  351. data/packages/gsutil/boto/boto/sqs/jsonmessage.py +43 -0
  352. data/packages/gsutil/boto/boto/sqs/message.py +253 -0
  353. data/packages/gsutil/boto/boto/sqs/queue.py +478 -0
  354. data/packages/gsutil/boto/boto/sqs/regioninfo.py +32 -0
  355. data/packages/gsutil/boto/boto/storage_uri.py +835 -0
  356. data/packages/gsutil/boto/boto/storage_uri.pyc +0 -0
  357. data/packages/gsutil/boto/boto/sts/__init__.py +55 -0
  358. data/packages/gsutil/boto/boto/sts/connection.py +207 -0
  359. data/packages/gsutil/boto/boto/sts/credentials.py +215 -0
  360. data/packages/gsutil/boto/boto/swf/__init__.py +60 -0
  361. data/packages/gsutil/boto/boto/swf/exceptions.py +44 -0
  362. data/packages/gsutil/boto/boto/swf/layer1.py +1512 -0
  363. data/packages/gsutil/boto/boto/swf/layer1_decisions.py +287 -0
  364. data/packages/gsutil/boto/boto/swf/layer2.py +342 -0
  365. data/packages/gsutil/boto/boto/utils.py +927 -0
  366. data/packages/gsutil/boto/boto/utils.pyc +0 -0
  367. data/packages/gsutil/boto/boto/vpc/__init__.py +910 -0
  368. data/packages/gsutil/boto/boto/vpc/customergateway.py +54 -0
  369. data/packages/gsutil/boto/boto/vpc/dhcpoptions.py +72 -0
  370. data/packages/gsutil/boto/boto/vpc/internetgateway.py +72 -0
  371. data/packages/gsutil/boto/boto/vpc/routetable.py +109 -0
  372. data/packages/gsutil/boto/boto/vpc/subnet.py +57 -0
  373. data/packages/gsutil/boto/boto/vpc/vpc.py +54 -0
  374. data/packages/gsutil/boto/boto/vpc/vpnconnection.py +60 -0
  375. data/packages/gsutil/boto/boto/vpc/vpngateway.py +83 -0
  376. data/packages/gsutil/boto/docs/BotoCheatSheet.pdf +0 -0
  377. data/packages/gsutil/boto/docs/Makefile +89 -0
  378. data/packages/gsutil/boto/docs/make.bat +113 -0
  379. data/packages/gsutil/boto/docs/source/_templates/layout.html +3 -0
  380. data/packages/gsutil/boto/docs/source/autoscale_tut.rst +220 -0
  381. data/packages/gsutil/boto/docs/source/boto_config_tut.rst +125 -0
  382. data/packages/gsutil/boto/docs/source/boto_theme/static/boto.css_t +239 -0
  383. data/packages/gsutil/boto/docs/source/boto_theme/static/pygments.css +61 -0
  384. data/packages/gsutil/boto/docs/source/boto_theme/theme.conf +3 -0
  385. data/packages/gsutil/boto/docs/source/cloudfront_tut.rst +196 -0
  386. data/packages/gsutil/boto/docs/source/cloudsearch_tut.rst +411 -0
  387. data/packages/gsutil/boto/docs/source/cloudwatch_tut.rst +116 -0
  388. data/packages/gsutil/boto/docs/source/conf.py +32 -0
  389. data/packages/gsutil/boto/docs/source/contributing.rst +204 -0
  390. data/packages/gsutil/boto/docs/source/documentation.rst +59 -0
  391. data/packages/gsutil/boto/docs/source/dynamodb_tut.rst +339 -0
  392. data/packages/gsutil/boto/docs/source/ec2_tut.rst +86 -0
  393. data/packages/gsutil/boto/docs/source/elb_tut.rst +257 -0
  394. data/packages/gsutil/boto/docs/source/emr_tut.rst +108 -0
  395. data/packages/gsutil/boto/docs/source/index.rst +146 -0
  396. data/packages/gsutil/boto/docs/source/rds_tut.rst +108 -0
  397. data/packages/gsutil/boto/docs/source/ref/autoscale.rst +62 -0
  398. data/packages/gsutil/boto/docs/source/ref/beanstalk.rst +26 -0
  399. data/packages/gsutil/boto/docs/source/ref/boto.rst +47 -0
  400. data/packages/gsutil/boto/docs/source/ref/cloudformation.rst +34 -0
  401. data/packages/gsutil/boto/docs/source/ref/cloudfront.rst +68 -0
  402. data/packages/gsutil/boto/docs/source/ref/cloudsearch.rst +59 -0
  403. data/packages/gsutil/boto/docs/source/ref/cloudwatch.rst +27 -0
  404. data/packages/gsutil/boto/docs/source/ref/contrib.rst +32 -0
  405. data/packages/gsutil/boto/docs/source/ref/datapipeline.rst +26 -0
  406. data/packages/gsutil/boto/docs/source/ref/dynamodb.rst +61 -0
  407. data/packages/gsutil/boto/docs/source/ref/ec2.rst +140 -0
  408. data/packages/gsutil/boto/docs/source/ref/ecs.rst +19 -0
  409. data/packages/gsutil/boto/docs/source/ref/elasticache.rst +19 -0
  410. data/packages/gsutil/boto/docs/source/ref/elastictranscoder.rst +26 -0
  411. data/packages/gsutil/boto/docs/source/ref/elb.rst +47 -0
  412. data/packages/gsutil/boto/docs/source/ref/emr.rst +34 -0
  413. data/packages/gsutil/boto/docs/source/ref/file.rst +34 -0
  414. data/packages/gsutil/boto/docs/source/ref/fps.rst +19 -0
  415. data/packages/gsutil/boto/docs/source/ref/glacier.rst +63 -0
  416. data/packages/gsutil/boto/docs/source/ref/gs.rst +72 -0
  417. data/packages/gsutil/boto/docs/source/ref/iam.rst +27 -0
  418. data/packages/gsutil/boto/docs/source/ref/index.rst +40 -0
  419. data/packages/gsutil/boto/docs/source/ref/manage.rst +47 -0
  420. data/packages/gsutil/boto/docs/source/ref/mturk.rst +54 -0
  421. data/packages/gsutil/boto/docs/source/ref/mws.rst +33 -0
  422. data/packages/gsutil/boto/docs/source/ref/pyami.rst +103 -0
  423. data/packages/gsutil/boto/docs/source/ref/rds.rst +47 -0
  424. data/packages/gsutil/boto/docs/source/ref/route53.rst +34 -0
  425. data/packages/gsutil/boto/docs/source/ref/s3.rst +111 -0
  426. data/packages/gsutil/boto/docs/source/ref/sdb.rst +45 -0
  427. data/packages/gsutil/boto/docs/source/ref/sdb_db.rst +83 -0
  428. data/packages/gsutil/boto/docs/source/ref/services.rst +61 -0
  429. data/packages/gsutil/boto/docs/source/ref/ses.rst +21 -0
  430. data/packages/gsutil/boto/docs/source/ref/sns.rst +17 -0
  431. data/packages/gsutil/boto/docs/source/ref/sqs.rst +61 -0
  432. data/packages/gsutil/boto/docs/source/ref/sts.rst +25 -0
  433. data/packages/gsutil/boto/docs/source/ref/swf.rst +22 -0
  434. data/packages/gsutil/boto/docs/source/ref/vpc.rst +54 -0
  435. data/packages/gsutil/boto/docs/source/s3_tut.rst +450 -0
  436. data/packages/gsutil/boto/docs/source/security_groups.rst +82 -0
  437. data/packages/gsutil/boto/docs/source/ses_tut.rst +171 -0
  438. data/packages/gsutil/boto/docs/source/simpledb_tut.rst +188 -0
  439. data/packages/gsutil/boto/docs/source/sqs_tut.rst +246 -0
  440. data/packages/gsutil/boto/docs/source/vpc_tut.rst +100 -0
  441. data/packages/gsutil/boto/pylintrc +305 -0
  442. data/packages/gsutil/boto/requirements.txt +10 -0
  443. data/packages/gsutil/boto/setup.py +89 -0
  444. data/packages/gsutil/boto/tests/__init__.py +20 -0
  445. data/packages/gsutil/boto/tests/db/test_lists.py +96 -0
  446. data/packages/gsutil/boto/tests/db/test_password.py +128 -0
  447. data/packages/gsutil/boto/tests/db/test_query.py +152 -0
  448. data/packages/gsutil/boto/tests/db/test_sequence.py +109 -0
  449. data/packages/gsutil/boto/tests/devpay/__init__.py +0 -0
  450. data/packages/gsutil/boto/tests/devpay/test_s3.py +181 -0
  451. data/packages/gsutil/boto/tests/fps/__init__.py +0 -0
  452. data/packages/gsutil/boto/tests/fps/test.py +100 -0
  453. data/packages/gsutil/boto/tests/fps/test_verify_signature.py +12 -0
  454. data/packages/gsutil/boto/tests/integration/__init__.py +0 -0
  455. data/packages/gsutil/boto/tests/integration/beanstalk/test_wrapper.py +209 -0
  456. data/packages/gsutil/boto/tests/integration/cloudformation/__init__.py +21 -0
  457. data/packages/gsutil/boto/tests/integration/cloudformation/test_cert_verification.py +40 -0
  458. data/packages/gsutil/boto/tests/integration/cloudformation/test_connection.py +110 -0
  459. data/packages/gsutil/boto/tests/integration/cloudsearch/__init__.py +21 -0
  460. data/packages/gsutil/boto/tests/integration/cloudsearch/test_cert_verification.py +40 -0
  461. data/packages/gsutil/boto/tests/integration/datapipeline/test_layer1.py +122 -0
  462. data/packages/gsutil/boto/tests/integration/dynamodb/__init__.py +20 -0
  463. data/packages/gsutil/boto/tests/integration/dynamodb/test_cert_verification.py +40 -0
  464. data/packages/gsutil/boto/tests/integration/dynamodb/test_layer1.py +266 -0
  465. data/packages/gsutil/boto/tests/integration/dynamodb/test_layer2.py +484 -0
  466. data/packages/gsutil/boto/tests/integration/dynamodb/test_table.py +84 -0
  467. data/packages/gsutil/boto/tests/integration/ec2/__init__.py +20 -0
  468. data/packages/gsutil/boto/tests/integration/ec2/autoscale/__init__.py +21 -0
  469. data/packages/gsutil/boto/tests/integration/ec2/autoscale/test_cert_verification.py +40 -0
  470. data/packages/gsutil/boto/tests/integration/ec2/autoscale/test_connection.py +167 -0
  471. data/packages/gsutil/boto/tests/integration/ec2/cloudwatch/__init__.py +20 -0
  472. data/packages/gsutil/boto/tests/integration/ec2/cloudwatch/test_cert_verification.py +40 -0
  473. data/packages/gsutil/boto/tests/integration/ec2/cloudwatch/test_connection.py +277 -0
  474. data/packages/gsutil/boto/tests/integration/ec2/elb/__init__.py +20 -0
  475. data/packages/gsutil/boto/tests/integration/ec2/elb/test_cert_verification.py +40 -0
  476. data/packages/gsutil/boto/tests/integration/ec2/elb/test_connection.py +130 -0
  477. data/packages/gsutil/boto/tests/integration/ec2/test_cert_verification.py +40 -0
  478. data/packages/gsutil/boto/tests/integration/ec2/test_connection.py +192 -0
  479. data/packages/gsutil/boto/tests/integration/ec2/vpc/__init__.py +0 -0
  480. data/packages/gsutil/boto/tests/integration/ec2/vpc/test_connection.py +95 -0
  481. data/packages/gsutil/boto/tests/integration/elasticache/__init__.py +0 -0
  482. data/packages/gsutil/boto/tests/integration/elasticache/test_layer1.py +67 -0
  483. data/packages/gsutil/boto/tests/integration/elastictranscoder/__init__.py +0 -0
  484. data/packages/gsutil/boto/tests/integration/elastictranscoder/test_cert_verification.py +35 -0
  485. data/packages/gsutil/boto/tests/integration/elastictranscoder/test_layer1.py +115 -0
  486. data/packages/gsutil/boto/tests/integration/emr/__init__.py +20 -0
  487. data/packages/gsutil/boto/tests/integration/emr/test_cert_verification.py +40 -0
  488. data/packages/gsutil/boto/tests/integration/glacier/__init__.py +22 -0
  489. data/packages/gsutil/boto/tests/integration/glacier/test_cert_verification.py +40 -0
  490. data/packages/gsutil/boto/tests/integration/glacier/test_layer1.py +44 -0
  491. data/packages/gsutil/boto/tests/integration/glacier/test_layer2.py +45 -0
  492. data/packages/gsutil/boto/tests/integration/gs/__init__.py +0 -0
  493. data/packages/gsutil/boto/tests/integration/gs/cb_test_harness.py +71 -0
  494. data/packages/gsutil/boto/tests/integration/gs/test_basic.py +379 -0
  495. data/packages/gsutil/boto/tests/integration/gs/test_generation_conditionals.py +399 -0
  496. data/packages/gsutil/boto/tests/integration/gs/test_resumable_downloads.py +358 -0
  497. data/packages/gsutil/boto/tests/integration/gs/test_resumable_uploads.py +525 -0
  498. data/packages/gsutil/boto/tests/integration/gs/test_storage_uri.py +125 -0
  499. data/packages/gsutil/boto/tests/integration/gs/test_versioning.py +268 -0
  500. data/packages/gsutil/boto/tests/integration/gs/testcase.py +116 -0
  501. data/packages/gsutil/boto/tests/integration/gs/util.py +63 -0
  502. data/packages/gsutil/boto/tests/integration/iam/__init__.py +20 -0
  503. data/packages/gsutil/boto/tests/integration/iam/test_cert_verification.py +40 -0
  504. data/packages/gsutil/boto/tests/integration/mws/__init__.py +0 -0
  505. data/packages/gsutil/boto/tests/integration/mws/test.py +100 -0
  506. data/packages/gsutil/boto/tests/integration/rds/__init__.py +21 -0
  507. data/packages/gsutil/boto/tests/integration/rds/test_cert_verification.py +40 -0
  508. data/packages/gsutil/boto/tests/integration/route53/__init__.py +20 -0
  509. data/packages/gsutil/boto/tests/integration/route53/test_cert_verification.py +40 -0
  510. data/packages/gsutil/boto/tests/integration/route53/test_zone.py +132 -0
  511. data/packages/gsutil/boto/tests/integration/s3/__init__.py +20 -0
  512. data/packages/gsutil/boto/tests/integration/s3/mock_storage_service.py +589 -0
  513. data/packages/gsutil/boto/tests/integration/s3/other_cacerts.txt +70 -0
  514. data/packages/gsutil/boto/tests/integration/s3/test_bucket.py +263 -0
  515. data/packages/gsutil/boto/tests/integration/s3/test_cert_verification.py +40 -0
  516. data/packages/gsutil/boto/tests/integration/s3/test_connection.py +245 -0
  517. data/packages/gsutil/boto/tests/integration/s3/test_cors.py +78 -0
  518. data/packages/gsutil/boto/tests/integration/s3/test_encryption.py +115 -0
  519. data/packages/gsutil/boto/tests/integration/s3/test_https_cert_validation.py +141 -0
  520. data/packages/gsutil/boto/tests/integration/s3/test_key.py +375 -0
  521. data/packages/gsutil/boto/tests/integration/s3/test_mfa.py +95 -0
  522. data/packages/gsutil/boto/tests/integration/s3/test_multidelete.py +181 -0
  523. data/packages/gsutil/boto/tests/integration/s3/test_multipart.py +139 -0
  524. data/packages/gsutil/boto/tests/integration/s3/test_pool.py +246 -0
  525. data/packages/gsutil/boto/tests/integration/s3/test_versioning.py +158 -0
  526. data/packages/gsutil/boto/tests/integration/sdb/__init__.py +20 -0
  527. data/packages/gsutil/boto/tests/integration/sdb/test_cert_verification.py +40 -0
  528. data/packages/gsutil/boto/tests/integration/sdb/test_connection.py +119 -0
  529. data/packages/gsutil/boto/tests/integration/ses/__init__.py +0 -0
  530. data/packages/gsutil/boto/tests/integration/ses/test_cert_verification.py +40 -0
  531. data/packages/gsutil/boto/tests/integration/ses/test_connection.py +38 -0
  532. data/packages/gsutil/boto/tests/integration/sns/__init__.py +20 -0
  533. data/packages/gsutil/boto/tests/integration/sns/test_cert_verification.py +40 -0
  534. data/packages/gsutil/boto/tests/integration/sqs/__init__.py +20 -0
  535. data/packages/gsutil/boto/tests/integration/sqs/test_cert_verification.py +40 -0
  536. data/packages/gsutil/boto/tests/integration/sqs/test_connection.py +217 -0
  537. data/packages/gsutil/boto/tests/integration/sts/__init__.py +20 -0
  538. data/packages/gsutil/boto/tests/integration/sts/test_cert_verification.py +40 -0
  539. data/packages/gsutil/boto/tests/integration/sts/test_session_token.py +65 -0
  540. data/packages/gsutil/boto/tests/integration/swf/__init__.py +0 -0
  541. data/packages/gsutil/boto/tests/integration/swf/test_cert_verification.py +40 -0
  542. data/packages/gsutil/boto/tests/integration/swf/test_layer1.py +246 -0
  543. data/packages/gsutil/boto/tests/integration/swf/test_layer1_workflow_execution.py +173 -0
  544. data/packages/gsutil/boto/tests/mturk/__init__.py +0 -0
  545. data/packages/gsutil/boto/tests/mturk/_init_environment.py +28 -0
  546. data/packages/gsutil/boto/tests/mturk/all_tests.py +24 -0
  547. data/packages/gsutil/boto/tests/mturk/cleanup_tests.py +47 -0
  548. data/packages/gsutil/boto/tests/mturk/common.py +45 -0
  549. data/packages/gsutil/boto/tests/mturk/create_free_text_question_regex.doctest +100 -0
  550. data/packages/gsutil/boto/tests/mturk/create_hit.doctest +92 -0
  551. data/packages/gsutil/boto/tests/mturk/create_hit_binary.doctest +94 -0
  552. data/packages/gsutil/boto/tests/mturk/create_hit_external.py +21 -0
  553. data/packages/gsutil/boto/tests/mturk/create_hit_from_hit_type.doctest +103 -0
  554. data/packages/gsutil/boto/tests/mturk/create_hit_test.py +21 -0
  555. data/packages/gsutil/boto/tests/mturk/create_hit_with_qualifications.py +16 -0
  556. data/packages/gsutil/boto/tests/mturk/hit_persistence.py +27 -0
  557. data/packages/gsutil/boto/tests/mturk/mocks.py +11 -0
  558. data/packages/gsutil/boto/tests/mturk/reviewable_hits.doctest +129 -0
  559. data/packages/gsutil/boto/tests/mturk/run-doctest.py +13 -0
  560. data/packages/gsutil/boto/tests/mturk/search_hits.doctest +16 -0
  561. data/packages/gsutil/boto/tests/mturk/selenium_support.py +61 -0
  562. data/packages/gsutil/boto/tests/mturk/support.py +7 -0
  563. data/packages/gsutil/boto/tests/mturk/test_disable_hit.py +11 -0
  564. data/packages/gsutil/boto/tests/test.py +59 -0
  565. data/packages/gsutil/boto/tests/unit/__init__.py +79 -0
  566. data/packages/gsutil/boto/tests/unit/auth/__init__.py +0 -0
  567. data/packages/gsutil/boto/tests/unit/auth/test_sigv4.py +73 -0
  568. data/packages/gsutil/boto/tests/unit/beanstalk/__init__.py +0 -0
  569. data/packages/gsutil/boto/tests/unit/beanstalk/test_layer1.py +128 -0
  570. data/packages/gsutil/boto/tests/unit/cloudformation/__init__.py +0 -0
  571. data/packages/gsutil/boto/tests/unit/cloudformation/test_connection.py +605 -0
  572. data/packages/gsutil/boto/tests/unit/cloudformation/test_stack.py +63 -0
  573. data/packages/gsutil/boto/tests/unit/cloudfront/__init__.py +0 -0
  574. data/packages/gsutil/boto/tests/unit/cloudfront/test_invalidation_list.py +113 -0
  575. data/packages/gsutil/boto/tests/unit/cloudfront/test_signed_urls.py +354 -0
  576. data/packages/gsutil/boto/tests/unit/cloudsearch/__init__.py +1 -0
  577. data/packages/gsutil/boto/tests/unit/cloudsearch/test_connection.py +241 -0
  578. data/packages/gsutil/boto/tests/unit/cloudsearch/test_document.py +324 -0
  579. data/packages/gsutil/boto/tests/unit/cloudsearch/test_search.py +325 -0
  580. data/packages/gsutil/boto/tests/unit/dynamodb/__init__.py +0 -0
  581. data/packages/gsutil/boto/tests/unit/dynamodb/test_batch.py +103 -0
  582. data/packages/gsutil/boto/tests/unit/dynamodb/test_layer2.py +119 -0
  583. data/packages/gsutil/boto/tests/unit/dynamodb/test_types.py +82 -0
  584. data/packages/gsutil/boto/tests/unit/ec2/__init__.py +0 -0
  585. data/packages/gsutil/boto/tests/unit/ec2/autoscale/__init__.py +0 -0
  586. data/packages/gsutil/boto/tests/unit/ec2/autoscale/test_group.py +162 -0
  587. data/packages/gsutil/boto/tests/unit/ec2/test_address.py +39 -0
  588. data/packages/gsutil/boto/tests/unit/ec2/test_blockdevicemapping.py +79 -0
  589. data/packages/gsutil/boto/tests/unit/ec2/test_connection.py +480 -0
  590. data/packages/gsutil/boto/tests/unit/ec2/test_instance.py +243 -0
  591. data/packages/gsutil/boto/tests/unit/ec2/test_networkinterface.py +140 -0
  592. data/packages/gsutil/boto/tests/unit/ec2/test_volume.py +248 -0
  593. data/packages/gsutil/boto/tests/unit/emr/test_emr_responses.py +373 -0
  594. data/packages/gsutil/boto/tests/unit/glacier/__init__.py +0 -0
  595. data/packages/gsutil/boto/tests/unit/glacier/test_concurrent.py +120 -0
  596. data/packages/gsutil/boto/tests/unit/glacier/test_job.py +60 -0
  597. data/packages/gsutil/boto/tests/unit/glacier/test_layer1.py +98 -0
  598. data/packages/gsutil/boto/tests/unit/glacier/test_layer2.py +266 -0
  599. data/packages/gsutil/boto/tests/unit/glacier/test_utils.py +116 -0
  600. data/packages/gsutil/boto/tests/unit/glacier/test_vault.py +100 -0
  601. data/packages/gsutil/boto/tests/unit/glacier/test_writer.py +185 -0
  602. data/packages/gsutil/boto/tests/unit/provider/__init__.py +0 -0
  603. data/packages/gsutil/boto/tests/unit/provider/test_provider.py +176 -0
  604. data/packages/gsutil/boto/tests/unit/rds/__init__.py +0 -0
  605. data/packages/gsutil/boto/tests/unit/rds/test_connection.py +131 -0
  606. data/packages/gsutil/boto/tests/unit/s3/__init__.py +0 -0
  607. data/packages/gsutil/boto/tests/unit/s3/test_cors_configuration.py +77 -0
  608. data/packages/gsutil/boto/tests/unit/s3/test_key.py +75 -0
  609. data/packages/gsutil/boto/tests/unit/s3/test_keyfile.py +101 -0
  610. data/packages/gsutil/boto/tests/unit/s3/test_lifecycle.py +97 -0
  611. data/packages/gsutil/boto/tests/unit/s3/test_tagging.py +47 -0
  612. data/packages/gsutil/boto/tests/unit/s3/test_uri.py +257 -0
  613. data/packages/gsutil/boto/tests/unit/s3/test_website.py +188 -0
  614. data/packages/gsutil/boto/tests/unit/sns/__init__.py +0 -0
  615. data/packages/gsutil/boto/tests/unit/sns/test_connection.py +99 -0
  616. data/packages/gsutil/boto/tests/unit/sqs/__init__.py +0 -0
  617. data/packages/gsutil/boto/tests/unit/sqs/test_connection.py +98 -0
  618. data/packages/gsutil/boto/tests/unit/sqs/test_queue.py +40 -0
  619. data/packages/gsutil/boto/tests/unit/sts/test_connection.py +74 -0
  620. data/packages/gsutil/boto/tests/unit/test_connection.py +60 -0
  621. data/packages/gsutil/boto/tests/unit/utils/test_utils.py +109 -0
  622. data/packages/gsutil/boto/tox.ini +8 -0
  623. data/packages/gsutil/gslib/README +5 -0
  624. data/packages/gsutil/gslib/__init__.py +22 -0
  625. data/packages/gsutil/gslib/__init__.pyc +0 -0
  626. data/packages/gsutil/gslib/addlhelp/__init__.py +15 -0
  627. data/packages/gsutil/gslib/addlhelp/acls.py +234 -0
  628. data/packages/gsutil/gslib/addlhelp/anon.py +57 -0
  629. data/packages/gsutil/gslib/addlhelp/command_opts.py +116 -0
  630. data/packages/gsutil/gslib/addlhelp/dev.py +139 -0
  631. data/packages/gsutil/gslib/addlhelp/metadata.py +186 -0
  632. data/packages/gsutil/gslib/addlhelp/naming.py +173 -0
  633. data/packages/gsutil/gslib/addlhelp/prod.py +160 -0
  634. data/packages/gsutil/gslib/addlhelp/projects.py +130 -0
  635. data/packages/gsutil/gslib/addlhelp/subdirs.py +110 -0
  636. data/packages/gsutil/gslib/addlhelp/support.py +86 -0
  637. data/packages/gsutil/gslib/addlhelp/versioning.py +242 -0
  638. data/packages/gsutil/gslib/addlhelp/wildcards.py +170 -0
  639. data/packages/gsutil/gslib/bucket_listing_ref.py +175 -0
  640. data/packages/gsutil/gslib/bucket_listing_ref.pyc +0 -0
  641. data/packages/gsutil/gslib/command.py +722 -0
  642. data/packages/gsutil/gslib/command.pyc +0 -0
  643. data/packages/gsutil/gslib/command_runner.py +101 -0
  644. data/packages/gsutil/gslib/command_runner.pyc +0 -0
  645. data/packages/gsutil/gslib/commands/__init__.py +15 -0
  646. data/packages/gsutil/gslib/commands/__init__.pyc +0 -0
  647. data/packages/gsutil/gslib/commands/cat.py +131 -0
  648. data/packages/gsutil/gslib/commands/cat.pyc +0 -0
  649. data/packages/gsutil/gslib/commands/chacl.py +532 -0
  650. data/packages/gsutil/gslib/commands/chacl.pyc +0 -0
  651. data/packages/gsutil/gslib/commands/config.py +694 -0
  652. data/packages/gsutil/gslib/commands/config.pyc +0 -0
  653. data/packages/gsutil/gslib/commands/cp.py +1818 -0
  654. data/packages/gsutil/gslib/commands/cp.pyc +0 -0
  655. data/packages/gsutil/gslib/commands/disablelogging.py +101 -0
  656. data/packages/gsutil/gslib/commands/disablelogging.pyc +0 -0
  657. data/packages/gsutil/gslib/commands/enablelogging.py +149 -0
  658. data/packages/gsutil/gslib/commands/enablelogging.pyc +0 -0
  659. data/packages/gsutil/gslib/commands/getacl.py +82 -0
  660. data/packages/gsutil/gslib/commands/getacl.pyc +0 -0
  661. data/packages/gsutil/gslib/commands/getcors.py +121 -0
  662. data/packages/gsutil/gslib/commands/getcors.pyc +0 -0
  663. data/packages/gsutil/gslib/commands/getdefacl.py +86 -0
  664. data/packages/gsutil/gslib/commands/getdefacl.pyc +0 -0
  665. data/packages/gsutil/gslib/commands/getlogging.py +137 -0
  666. data/packages/gsutil/gslib/commands/getlogging.pyc +0 -0
  667. data/packages/gsutil/gslib/commands/getversioning.py +116 -0
  668. data/packages/gsutil/gslib/commands/getversioning.pyc +0 -0
  669. data/packages/gsutil/gslib/commands/getwebcfg.py +122 -0
  670. data/packages/gsutil/gslib/commands/getwebcfg.pyc +0 -0
  671. data/packages/gsutil/gslib/commands/help.py +218 -0
  672. data/packages/gsutil/gslib/commands/help.pyc +0 -0
  673. data/packages/gsutil/gslib/commands/ls.py +578 -0
  674. data/packages/gsutil/gslib/commands/ls.pyc +0 -0
  675. data/packages/gsutil/gslib/commands/mb.py +172 -0
  676. data/packages/gsutil/gslib/commands/mb.pyc +0 -0
  677. data/packages/gsutil/gslib/commands/mv.py +159 -0
  678. data/packages/gsutil/gslib/commands/mv.pyc +0 -0
  679. data/packages/gsutil/gslib/commands/perfdiag.py +903 -0
  680. data/packages/gsutil/gslib/commands/perfdiag.pyc +0 -0
  681. data/packages/gsutil/gslib/commands/rb.py +113 -0
  682. data/packages/gsutil/gslib/commands/rb.pyc +0 -0
  683. data/packages/gsutil/gslib/commands/rm.py +239 -0
  684. data/packages/gsutil/gslib/commands/rm.pyc +0 -0
  685. data/packages/gsutil/gslib/commands/setacl.py +138 -0
  686. data/packages/gsutil/gslib/commands/setacl.pyc +0 -0
  687. data/packages/gsutil/gslib/commands/setcors.py +145 -0
  688. data/packages/gsutil/gslib/commands/setcors.pyc +0 -0
  689. data/packages/gsutil/gslib/commands/setdefacl.py +105 -0
  690. data/packages/gsutil/gslib/commands/setdefacl.pyc +0 -0
  691. data/packages/gsutil/gslib/commands/setmeta.py +428 -0
  692. data/packages/gsutil/gslib/commands/setmeta.pyc +0 -0
  693. data/packages/gsutil/gslib/commands/setversioning.py +114 -0
  694. data/packages/gsutil/gslib/commands/setversioning.pyc +0 -0
  695. data/packages/gsutil/gslib/commands/setwebcfg.py +190 -0
  696. data/packages/gsutil/gslib/commands/setwebcfg.pyc +0 -0
  697. data/packages/gsutil/gslib/commands/test.py +228 -0
  698. data/packages/gsutil/gslib/commands/test.pyc +0 -0
  699. data/packages/gsutil/gslib/commands/update.py +305 -0
  700. data/packages/gsutil/gslib/commands/update.pyc +0 -0
  701. data/packages/gsutil/gslib/commands/version.py +150 -0
  702. data/packages/gsutil/gslib/commands/version.pyc +0 -0
  703. data/packages/gsutil/gslib/exception.py +76 -0
  704. data/packages/gsutil/gslib/exception.pyc +0 -0
  705. data/packages/gsutil/gslib/help_provider.py +81 -0
  706. data/packages/gsutil/gslib/help_provider.pyc +0 -0
  707. data/packages/gsutil/gslib/name_expansion.py +550 -0
  708. data/packages/gsutil/gslib/name_expansion.pyc +0 -0
  709. data/packages/gsutil/gslib/no_op_auth_plugin.py +30 -0
  710. data/packages/gsutil/gslib/plurality_checkable_iterator.py +56 -0
  711. data/packages/gsutil/gslib/plurality_checkable_iterator.pyc +0 -0
  712. data/packages/gsutil/gslib/project_id.py +67 -0
  713. data/packages/gsutil/gslib/project_id.pyc +0 -0
  714. data/packages/gsutil/gslib/storage_uri_builder.py +56 -0
  715. data/packages/gsutil/gslib/storage_uri_builder.pyc +0 -0
  716. data/packages/gsutil/gslib/tests/__init__.py +15 -0
  717. data/packages/gsutil/gslib/tests/__init__.pyc +0 -0
  718. data/packages/gsutil/gslib/tests/test_chacl.py +236 -0
  719. data/packages/gsutil/gslib/tests/test_cp.py +267 -0
  720. data/packages/gsutil/gslib/tests/test_data/test.gif +0 -0
  721. data/packages/gsutil/gslib/tests/test_data/test.mp3 +0 -0
  722. data/packages/gsutil/gslib/tests/test_ls.py +66 -0
  723. data/packages/gsutil/gslib/tests/test_mv.py +69 -0
  724. data/packages/gsutil/gslib/tests/test_naming.py +989 -0
  725. data/packages/gsutil/gslib/tests/test_perfdiag.py +41 -0
  726. data/packages/gsutil/gslib/tests/test_plurality_checkable_iterator.py +67 -0
  727. data/packages/gsutil/gslib/tests/test_rm.py +143 -0
  728. data/packages/gsutil/gslib/tests/test_setacl.py +152 -0
  729. data/packages/gsutil/gslib/tests/test_setcors.py +168 -0
  730. data/packages/gsutil/gslib/tests/test_setmeta.py +91 -0
  731. data/packages/gsutil/gslib/tests/test_setversioning.py +44 -0
  732. data/packages/gsutil/gslib/tests/test_setwebcfg.py +63 -0
  733. data/packages/gsutil/gslib/tests/test_thread_pool.py +92 -0
  734. data/packages/gsutil/gslib/tests/test_wildcard_iterator.py +364 -0
  735. data/packages/gsutil/gslib/tests/testcase/__init__.py +18 -0
  736. data/packages/gsutil/gslib/tests/testcase/base.py +89 -0
  737. data/packages/gsutil/gslib/tests/testcase/integration_testcase.py +197 -0
  738. data/packages/gsutil/gslib/tests/testcase/unit_testcase.py +230 -0
  739. data/packages/gsutil/gslib/tests/util.py +125 -0
  740. data/packages/gsutil/gslib/tests/util.pyc +0 -0
  741. data/packages/gsutil/gslib/thread_pool.py +79 -0
  742. data/packages/gsutil/gslib/thread_pool.pyc +0 -0
  743. data/packages/gsutil/gslib/util.py +151 -0
  744. data/packages/gsutil/gslib/util.pyc +0 -0
  745. data/packages/gsutil/gslib/wildcard_iterator.py +492 -0
  746. data/packages/gsutil/gslib/wildcard_iterator.pyc +0 -0
  747. data/packages/gsutil/gsutil +377 -0
  748. data/packages/gsutil/gsutil.spec.in +75 -0
  749. data/packages/gsutil/oauth2_plugin/__init__.py +22 -0
  750. data/packages/gsutil/oauth2_plugin/__init__.pyc +0 -0
  751. data/packages/gsutil/oauth2_plugin/oauth2_client.py +642 -0
  752. data/packages/gsutil/oauth2_plugin/oauth2_client.pyc +0 -0
  753. data/packages/gsutil/oauth2_plugin/oauth2_client_test.py +374 -0
  754. data/packages/gsutil/oauth2_plugin/oauth2_helper.py +110 -0
  755. data/packages/gsutil/oauth2_plugin/oauth2_helper.pyc +0 -0
  756. data/packages/gsutil/oauth2_plugin/oauth2_plugin.py +24 -0
  757. data/packages/gsutil/oauth2_plugin/oauth2_plugin.pyc +0 -0
  758. data/packages/gsutil/pkg_gen.sh +54 -0
  759. data/packages/gsutil/pkg_util.py +60 -0
  760. data/packages/gsutil/setup.py +141 -0
  761. data/packages/gsutil/third_party/__init__.py +0 -0
  762. data/packages/gsutil/third_party/__init__.pyc +0 -0
  763. data/packages/gsutil/third_party/fancy_urllib/README +21 -0
  764. data/packages/gsutil/third_party/fancy_urllib/__init__.py +398 -0
  765. data/packages/gsutil/third_party/fancy_urllib/__init__.pyc +0 -0
  766. data/tasks/rubygem.rake +3 -1
  767. metadata +770 -7
  768. metadata.gz.sig +0 -0
@@ -0,0 +1,210 @@
1
+ # Copyright (c) 2012 Mitch Garnaat http://garnaat.org/
2
+ # Copyright (c) 2012 Amazon.com, Inc. or its affiliates. All Rights Reserved
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a
5
+ # copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish, dis-
8
+ # tribute, sublicense, and/or sell copies of the Software, and to permit
9
+ # persons to whom the Software is furnished to do so, subject to the fol-
10
+ # lowing conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included
13
+ # in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17
+ # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
18
+ # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
+ # IN THE SOFTWARE.
22
+ #
23
+
24
+
25
+ class CORSRule(object):
26
+ """
27
+ CORS rule for a bucket.
28
+
29
+ :ivar id: A unique identifier for the rule. The ID value can be
30
+ up to 255 characters long. The IDs help you find a rule in
31
+ the configuration.
32
+
33
+ :ivar allowed_methods: An HTTP method that you want to allow the
34
+ origin to execute. Each CORSRule must identify at least one
35
+ origin and one method. Valid values are:
36
+ GET|PUT|HEAD|POST|DELETE
37
+
38
+ :ivar allowed_origin: An origin that you want to allow cross-domain
39
+ requests from. This can contain at most one * wild character.
40
+ Each CORSRule must identify at least one origin and one method.
41
+ The origin value can include at most one '*' wild character.
42
+ For example, "http://*.example.com". You can also specify
43
+ only * as the origin value allowing all origins cross-domain access.
44
+
45
+ :ivar allowed_header: Specifies which headers are allowed in a
46
+ pre-flight OPTIONS request via the
47
+ Access-Control-Request-Headers header. Each header name
48
+ specified in the Access-Control-Request-Headers header must
49
+ have a corresponding entry in the rule. Amazon S3 will send
50
+ only the allowed headers in a response that were requested.
51
+ This can contain at most one * wild character.
52
+
53
+ :ivar max_age_seconds: The time in seconds that your browser is to
54
+ cache the preflight response for the specified resource.
55
+
56
+ :ivar expose_header: One or more headers in the response that you
57
+ want customers to be able to access from their applications
58
+ (for example, from a JavaScript XMLHttpRequest object). You
59
+ add one ExposeHeader element in the rule for each header.
60
+ """
61
+
62
+ def __init__(self, allowed_method=None, allowed_origin=None,
63
+ id=None, allowed_header=None, max_age_seconds=None,
64
+ expose_header=None):
65
+ if allowed_method is None:
66
+ allowed_method = []
67
+ self.allowed_method = allowed_method
68
+ if allowed_origin is None:
69
+ allowed_origin = []
70
+ self.allowed_origin = allowed_origin
71
+ self.id = id
72
+ if allowed_header is None:
73
+ allowed_header = []
74
+ self.allowed_header = allowed_header
75
+ self.max_age_seconds = max_age_seconds
76
+ if expose_header is None:
77
+ expose_header = []
78
+ self.expose_header = expose_header
79
+
80
+ def __repr__(self):
81
+ return '<Rule: %s>' % self.id
82
+
83
+ def startElement(self, name, attrs, connection):
84
+ return None
85
+
86
+ def endElement(self, name, value, connection):
87
+ if name == 'ID':
88
+ self.id = value
89
+ elif name == 'AllowedMethod':
90
+ self.allowed_method.append(value)
91
+ elif name == 'AllowedOrigin':
92
+ self.allowed_origin.append(value)
93
+ elif name == 'AllowedHeader':
94
+ self.allowed_header.append(value)
95
+ elif name == 'MaxAgeSeconds':
96
+ self.max_age_seconds = int(value)
97
+ elif name == 'ExposeHeader':
98
+ self.expose_header.append(value)
99
+ else:
100
+ setattr(self, name, value)
101
+
102
+ def to_xml(self):
103
+ s = '<CORSRule>'
104
+ for allowed_method in self.allowed_method:
105
+ s += '<AllowedMethod>%s</AllowedMethod>' % allowed_method
106
+ for allowed_origin in self.allowed_origin:
107
+ s += '<AllowedOrigin>%s</AllowedOrigin>' % allowed_origin
108
+ for allowed_header in self.allowed_header:
109
+ s += '<AllowedHeader>%s</AllowedHeader>' % allowed_header
110
+ for expose_header in self.expose_header:
111
+ s += '<ExposeHeader>%s</ExposeHeader>' % expose_header
112
+ if self.max_age_seconds:
113
+ s += '<MaxAgeSeconds>%d</MaxAgeSeconds>' % self.max_age_seconds
114
+ if self.id:
115
+ s += '<ID>%s</ID>' % self.id
116
+ s += '</CORSRule>'
117
+ return s
118
+
119
+
120
+ class CORSConfiguration(list):
121
+ """
122
+ A container for the rules associated with a CORS configuration.
123
+ """
124
+
125
+ def startElement(self, name, attrs, connection):
126
+ if name == 'CORSRule':
127
+ rule = CORSRule()
128
+ self.append(rule)
129
+ return rule
130
+ return None
131
+
132
+ def endElement(self, name, value, connection):
133
+ setattr(self, name, value)
134
+
135
+ def to_xml(self):
136
+ """
137
+ Returns a string containing the XML version of the Lifecycle
138
+ configuration as defined by S3.
139
+ """
140
+ s = '<CORSConfiguration>'
141
+ for rule in self:
142
+ s += rule.to_xml()
143
+ s += '</CORSConfiguration>'
144
+ return s
145
+
146
+ def add_rule(self, allowed_method, allowed_origin,
147
+ id=None, allowed_header=None, max_age_seconds=None,
148
+ expose_header=None):
149
+ """
150
+ Add a rule to this CORS configuration. This only adds
151
+ the rule to the local copy. To install the new rule(s) on
152
+ the bucket, you need to pass this CORS config object
153
+ to the set_cors method of the Bucket object.
154
+
155
+ :type allowed_methods: list of str
156
+ :param allowed_methods: An HTTP method that you want to allow the
157
+ origin to execute. Each CORSRule must identify at least one
158
+ origin and one method. Valid values are:
159
+ GET|PUT|HEAD|POST|DELETE
160
+
161
+ :type allowed_origin: list of str
162
+ :param allowed_origin: An origin that you want to allow cross-domain
163
+ requests from. This can contain at most one * wild character.
164
+ Each CORSRule must identify at least one origin and one method.
165
+ The origin value can include at most one '*' wild character.
166
+ For example, "http://*.example.com". You can also specify
167
+ only * as the origin value allowing all origins
168
+ cross-domain access.
169
+
170
+ :type id: str
171
+ :param id: A unique identifier for the rule. The ID value can be
172
+ up to 255 characters long. The IDs help you find a rule in
173
+ the configuration.
174
+
175
+ :type allowed_header: list of str
176
+ :param allowed_header: Specifies which headers are allowed in a
177
+ pre-flight OPTIONS request via the
178
+ Access-Control-Request-Headers header. Each header name
179
+ specified in the Access-Control-Request-Headers header must
180
+ have a corresponding entry in the rule. Amazon S3 will send
181
+ only the allowed headers in a response that were requested.
182
+ This can contain at most one * wild character.
183
+
184
+ :type max_age_seconds: int
185
+ :param max_age_seconds: The time in seconds that your browser is to
186
+ cache the preflight response for the specified resource.
187
+
188
+ :type expose_header: list of str
189
+ :param expose_header: One or more headers in the response that you
190
+ want customers to be able to access from their applications
191
+ (for example, from a JavaScript XMLHttpRequest object). You
192
+ add one ExposeHeader element in the rule for each header.
193
+ """
194
+ if not isinstance(allowed_method, (list, tuple)):
195
+ allowed_method = [allowed_method]
196
+ if not isinstance(allowed_origin, (list, tuple)):
197
+ allowed_origin = [allowed_origin]
198
+ if not isinstance(allowed_origin, (list, tuple)):
199
+ if allowed_origin is None:
200
+ allowed_origin = []
201
+ else:
202
+ allowed_origin = [allowed_origin]
203
+ if not isinstance(expose_header, (list, tuple)):
204
+ if expose_header is None:
205
+ expose_header = []
206
+ else:
207
+ expose_header = [expose_header]
208
+ rule = CORSRule(allowed_method, allowed_origin, id, allowed_header,
209
+ max_age_seconds, expose_header)
210
+ self.append(rule)
@@ -0,0 +1,55 @@
1
+ # Copyright (c) 2006-2010 Mitch Garnaat http://garnaat.org/
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
+ from boto.s3.user import User
23
+
24
+ class DeleteMarker:
25
+ def __init__(self, bucket=None, name=None):
26
+ self.bucket = bucket
27
+ self.name = name
28
+ self.version_id = None
29
+ self.is_latest = False
30
+ self.last_modified = None
31
+ self.owner = None
32
+
33
+ def startElement(self, name, attrs, connection):
34
+ if name == 'Owner':
35
+ self.owner = User(self)
36
+ return self.owner
37
+ else:
38
+ return None
39
+
40
+ def endElement(self, name, value, connection):
41
+ if name == 'Key':
42
+ self.name = value
43
+ elif name == 'IsLatest':
44
+ if value == 'true':
45
+ self.is_latest = True
46
+ else:
47
+ self.is_latest = False
48
+ elif name == 'LastModified':
49
+ self.last_modified = value
50
+ elif name == 'Owner':
51
+ pass
52
+ elif name == 'VersionId':
53
+ self.version_id = value
54
+ else:
55
+ setattr(self, name, value)
@@ -0,0 +1,1712 @@
1
+ # Copyright (c) 2006-2012 Mitch Garnaat http://garnaat.org/
2
+ # Copyright (c) 2011, Nexenta Systems Inc.
3
+ # Copyright (c) 2012 Amazon.com, Inc. or its affiliates. All Rights Reserved
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a
6
+ # copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish, dis-
9
+ # tribute, sublicense, and/or sell copies of the Software, and to permit
10
+ # persons to whom the Software is furnished to do so, subject to the fol-
11
+ # lowing conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included
14
+ # in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
18
+ # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
19
+ # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
+ # IN THE SOFTWARE.
23
+
24
+ import mimetypes
25
+ import os
26
+ import re
27
+ import rfc822
28
+ import StringIO
29
+ import base64
30
+ import binascii
31
+ import math
32
+ import urllib
33
+ import boto.utils
34
+ from boto.exception import BotoClientError
35
+ from boto.provider import Provider
36
+ from boto.s3.keyfile import KeyFile
37
+ from boto.s3.user import User
38
+ from boto import UserAgent
39
+ from boto.utils import compute_md5
40
+ try:
41
+ from hashlib import md5
42
+ except ImportError:
43
+ from md5 import md5
44
+
45
+
46
+ class Key(object):
47
+ """
48
+ Represents a key (object) in an S3 bucket.
49
+
50
+ :ivar bucket: The parent :class:`boto.s3.bucket.Bucket`.
51
+ :ivar name: The name of this Key object.
52
+ :ivar metadata: A dictionary containing user metadata that you
53
+ wish to store with the object or that has been retrieved from
54
+ an existing object.
55
+ :ivar cache_control: The value of the `Cache-Control` HTTP header.
56
+ :ivar content_type: The value of the `Content-Type` HTTP header.
57
+ :ivar content_encoding: The value of the `Content-Encoding` HTTP header.
58
+ :ivar content_disposition: The value of the `Content-Disposition` HTTP
59
+ header.
60
+ :ivar content_language: The value of the `Content-Language` HTTP header.
61
+ :ivar etag: The `etag` associated with this object.
62
+ :ivar last_modified: The string timestamp representing the last
63
+ time this object was modified in S3.
64
+ :ivar owner: The ID of the owner of this object.
65
+ :ivar storage_class: The storage class of the object. Currently, one of:
66
+ STANDARD | REDUCED_REDUNDANCY | GLACIER
67
+ :ivar md5: The MD5 hash of the contents of the object.
68
+ :ivar size: The size, in bytes, of the object.
69
+ :ivar version_id: The version ID of this object, if it is a versioned
70
+ object.
71
+ :ivar encrypted: Whether the object is encrypted while at rest on
72
+ the server.
73
+ """
74
+
75
+ DefaultContentType = 'application/octet-stream'
76
+
77
+ RestoreBody = """<?xml version="1.0" encoding="UTF-8"?>
78
+ <RestoreRequest xmlns="http://s3.amazonaws.com/doc/2006-03-01">
79
+ <Days>%s</Days>
80
+ </RestoreRequest>"""
81
+
82
+
83
+ BufferSize = 8192
84
+
85
+ # The object metadata fields a user can set, other than custom metadata
86
+ # fields (i.e., those beginning with a provider-specific prefix like
87
+ # x-amz-meta).
88
+ base_user_settable_fields = set(["cache-control", "content-disposition",
89
+ "content-encoding", "content-language",
90
+ "content-md5", "content-type"])
91
+ _underscore_base_user_settable_fields = set()
92
+ for f in base_user_settable_fields:
93
+ _underscore_base_user_settable_fields.add(f.replace('-', '_'))
94
+
95
+
96
+
97
+ def __init__(self, bucket=None, name=None):
98
+ self.bucket = bucket
99
+ self.name = name
100
+ self.metadata = {}
101
+ self.cache_control = None
102
+ self.content_type = self.DefaultContentType
103
+ self.content_encoding = None
104
+ self.content_disposition = None
105
+ self.content_language = None
106
+ self.filename = None
107
+ self.etag = None
108
+ self.is_latest = False
109
+ self.last_modified = None
110
+ self.owner = None
111
+ self.storage_class = 'STANDARD'
112
+ self.md5 = None
113
+ self.base64md5 = None
114
+ self.path = None
115
+ self.resp = None
116
+ self.mode = None
117
+ self.size = None
118
+ self.version_id = None
119
+ self.source_version_id = None
120
+ self.delete_marker = False
121
+ self.encrypted = None
122
+ # If the object is being restored, this attribute will be set to True.
123
+ # If the object is restored, it will be set to False. Otherwise this
124
+ # value will be None. If the restore is completed (ongoing_restore =
125
+ # False), the expiry_date will be populated with the expiry date of the
126
+ # restored object.
127
+ self.ongoing_restore = None
128
+ self.expiry_date = None
129
+
130
+ def __repr__(self):
131
+ if self.bucket:
132
+ return '<Key: %s,%s>' % (self.bucket.name, self.name)
133
+ else:
134
+ return '<Key: None,%s>' % self.name
135
+
136
+ def __getattr__(self, name):
137
+ if name == 'key':
138
+ return self.name
139
+ else:
140
+ raise AttributeError
141
+
142
+ def __setattr__(self, name, value):
143
+ if name == 'key':
144
+ self.__dict__['name'] = value
145
+ else:
146
+ self.__dict__[name] = value
147
+
148
+ def __iter__(self):
149
+ return self
150
+
151
+ @property
152
+ def provider(self):
153
+ provider = None
154
+ if self.bucket and self.bucket.connection:
155
+ provider = self.bucket.connection.provider
156
+ return provider
157
+
158
+ def get_md5_from_hexdigest(self, md5_hexdigest):
159
+ """
160
+ A utility function to create the 2-tuple (md5hexdigest, base64md5)
161
+ from just having a precalculated md5_hexdigest.
162
+ """
163
+ digest = binascii.unhexlify(md5_hexdigest)
164
+ base64md5 = base64.encodestring(digest)
165
+ if base64md5[-1] == '\n':
166
+ base64md5 = base64md5[0:-1]
167
+ return (md5_hexdigest, base64md5)
168
+
169
+ def handle_encryption_headers(self, resp):
170
+ provider = self.bucket.connection.provider
171
+ if provider.server_side_encryption_header:
172
+ self.encrypted = resp.getheader(provider.server_side_encryption_header, None)
173
+ else:
174
+ self.encrypted = None
175
+
176
+ def handle_version_headers(self, resp, force=False):
177
+ provider = self.bucket.connection.provider
178
+ # If the Key object already has a version_id attribute value, it
179
+ # means that it represents an explicit version and the user is
180
+ # doing a get_contents_*(version_id=<foo>) to retrieve another
181
+ # version of the Key. In that case, we don't really want to
182
+ # overwrite the version_id in this Key object. Comprende?
183
+ if self.version_id is None or force:
184
+ self.version_id = resp.getheader(provider.version_id, None)
185
+ self.source_version_id = resp.getheader(provider.copy_source_version_id,
186
+ None)
187
+ if resp.getheader(provider.delete_marker, 'false') == 'true':
188
+ self.delete_marker = True
189
+ else:
190
+ self.delete_marker = False
191
+
192
+ def handle_restore_headers(self, response):
193
+ header = response.getheader('x-amz-restore')
194
+ if header is None:
195
+ return
196
+ parts = header.split(',', 1)
197
+ for part in parts:
198
+ key, val = [i.strip() for i in part.split('=')]
199
+ val = val.replace('"', '')
200
+ if key == 'ongoing-request':
201
+ self.ongoing_restore = True if val.lower() == 'true' else False
202
+ elif key == 'expiry-date':
203
+ self.expiry_date = val
204
+
205
+ def open_read(self, headers=None, query_args='',
206
+ override_num_retries=None, response_headers=None):
207
+ """
208
+ Open this key for reading
209
+
210
+ :type headers: dict
211
+ :param headers: Headers to pass in the web request
212
+
213
+ :type query_args: string
214
+ :param query_args: Arguments to pass in the query string
215
+ (ie, 'torrent')
216
+
217
+ :type override_num_retries: int
218
+ :param override_num_retries: If not None will override configured
219
+ num_retries parameter for underlying GET.
220
+
221
+ :type response_headers: dict
222
+ :param response_headers: A dictionary containing HTTP
223
+ headers/values that will override any headers associated
224
+ with the stored object in the response. See
225
+ http://goo.gl/EWOPb for details.
226
+ """
227
+ if self.resp == None:
228
+ self.mode = 'r'
229
+
230
+ provider = self.bucket.connection.provider
231
+ self.resp = self.bucket.connection.make_request(
232
+ 'GET', self.bucket.name, self.name, headers,
233
+ query_args=query_args,
234
+ override_num_retries=override_num_retries)
235
+ if self.resp.status < 199 or self.resp.status > 299:
236
+ body = self.resp.read()
237
+ raise provider.storage_response_error(self.resp.status,
238
+ self.resp.reason, body)
239
+ response_headers = self.resp.msg
240
+ self.metadata = boto.utils.get_aws_metadata(response_headers,
241
+ provider)
242
+ for name, value in response_headers.items():
243
+ # To get correct size for Range GETs, use Content-Range
244
+ # header if one was returned. If not, use Content-Length
245
+ # header.
246
+ if (name.lower() == 'content-length' and
247
+ 'Content-Range' not in response_headers):
248
+ self.size = int(value)
249
+ elif name.lower() == 'content-range':
250
+ end_range = re.sub('.*/(.*)', '\\1', value)
251
+ self.size = int(end_range)
252
+ elif name.lower() == 'etag':
253
+ self.etag = value
254
+ elif name.lower() == 'content-type':
255
+ self.content_type = value
256
+ elif name.lower() == 'content-encoding':
257
+ self.content_encoding = value
258
+ elif name.lower() == 'content-language':
259
+ self.content_language = value
260
+ elif name.lower() == 'last-modified':
261
+ self.last_modified = value
262
+ elif name.lower() == 'cache-control':
263
+ self.cache_control = value
264
+ elif name.lower() == 'content-disposition':
265
+ self.content_disposition = value
266
+ self.handle_version_headers(self.resp)
267
+ self.handle_encryption_headers(self.resp)
268
+
269
+ def open_write(self, headers=None, override_num_retries=None):
270
+ """
271
+ Open this key for writing.
272
+ Not yet implemented
273
+
274
+ :type headers: dict
275
+ :param headers: Headers to pass in the write request
276
+
277
+ :type override_num_retries: int
278
+ :param override_num_retries: If not None will override configured
279
+ num_retries parameter for underlying PUT.
280
+ """
281
+ raise BotoClientError('Not Implemented')
282
+
283
+ def open(self, mode='r', headers=None, query_args=None,
284
+ override_num_retries=None):
285
+ if mode == 'r':
286
+ self.mode = 'r'
287
+ self.open_read(headers=headers, query_args=query_args,
288
+ override_num_retries=override_num_retries)
289
+ elif mode == 'w':
290
+ self.mode = 'w'
291
+ self.open_write(headers=headers,
292
+ override_num_retries=override_num_retries)
293
+ else:
294
+ raise BotoClientError('Invalid mode: %s' % mode)
295
+
296
+ closed = False
297
+
298
+ def close(self, fast=False):
299
+ """
300
+ Close this key.
301
+
302
+ :type fast: bool
303
+ :param fast: True if you want the connection to be closed without first
304
+ reading the content. This should only be used in cases where subsequent
305
+ calls don't need to return the content from the open HTTP connection.
306
+ Note: As explained at
307
+ http://docs.python.org/2/library/httplib.html#httplib.HTTPConnection.getresponse,
308
+ callers must read the whole response before sending a new request to the
309
+ server. Calling Key.close(fast=True) and making a subsequent request to
310
+ the server will work because boto will get an httplib exception and
311
+ close/reopen the connection.
312
+
313
+ """
314
+ if self.resp and not fast:
315
+ self.resp.read()
316
+ self.resp = None
317
+ self.mode = None
318
+ self.closed = True
319
+
320
+ def next(self):
321
+ """
322
+ By providing a next method, the key object supports use as an iterator.
323
+ For example, you can now say:
324
+
325
+ for bytes in key:
326
+ write bytes to a file or whatever
327
+
328
+ All of the HTTP connection stuff is handled for you.
329
+ """
330
+ self.open_read()
331
+ data = self.resp.read(self.BufferSize)
332
+ if not data:
333
+ self.close()
334
+ raise StopIteration
335
+ return data
336
+
337
+ def read(self, size=0):
338
+ self.open_read()
339
+ if size == 0:
340
+ data = self.resp.read()
341
+ else:
342
+ data = self.resp.read(size)
343
+ if not data:
344
+ self.close()
345
+ return data
346
+
347
+ def change_storage_class(self, new_storage_class, dst_bucket=None,
348
+ validate_dst_bucket=True):
349
+ """
350
+ Change the storage class of an existing key.
351
+ Depending on whether a different destination bucket is supplied
352
+ or not, this will either move the item within the bucket, preserving
353
+ all metadata and ACL info bucket changing the storage class or it
354
+ will copy the item to the provided destination bucket, also
355
+ preserving metadata and ACL info.
356
+
357
+ :type new_storage_class: string
358
+ :param new_storage_class: The new storage class for the Key.
359
+ Possible values are:
360
+ * STANDARD
361
+ * REDUCED_REDUNDANCY
362
+
363
+ :type dst_bucket: string
364
+ :param dst_bucket: The name of a destination bucket. If not
365
+ provided the current bucket of the key will be used.
366
+
367
+ :type validate_dst_bucket: bool
368
+ :param validate_dst_bucket: If True, will validate the dst_bucket
369
+ by using an extra list request.
370
+ """
371
+ if new_storage_class == 'STANDARD':
372
+ return self.copy(self.bucket.name, self.name,
373
+ reduced_redundancy=False, preserve_acl=True,
374
+ validate_dst_bucket=validate_dst_bucket)
375
+ elif new_storage_class == 'REDUCED_REDUNDANCY':
376
+ return self.copy(self.bucket.name, self.name,
377
+ reduced_redundancy=True, preserve_acl=True,
378
+ validate_dst_bucket=validate_dst_bucket)
379
+ else:
380
+ raise BotoClientError('Invalid storage class: %s' %
381
+ new_storage_class)
382
+
383
+ def copy(self, dst_bucket, dst_key, metadata=None,
384
+ reduced_redundancy=False, preserve_acl=False,
385
+ encrypt_key=False, validate_dst_bucket=True):
386
+ """
387
+ Copy this Key to another bucket.
388
+
389
+ :type dst_bucket: string
390
+ :param dst_bucket: The name of the destination bucket
391
+
392
+ :type dst_key: string
393
+ :param dst_key: The name of the destination key
394
+
395
+ :type metadata: dict
396
+ :param metadata: Metadata to be associated with new key. If
397
+ metadata is supplied, it will replace the metadata of the
398
+ source key being copied. If no metadata is supplied, the
399
+ source key's metadata will be copied to the new key.
400
+
401
+ :type reduced_redundancy: bool
402
+ :param reduced_redundancy: If True, this will force the
403
+ storage class of the new Key to be REDUCED_REDUNDANCY
404
+ regardless of the storage class of the key being copied.
405
+ The Reduced Redundancy Storage (RRS) feature of S3,
406
+ provides lower redundancy at lower storage cost.
407
+
408
+ :type preserve_acl: bool
409
+ :param preserve_acl: If True, the ACL from the source key will
410
+ be copied to the destination key. If False, the
411
+ destination key will have the default ACL. Note that
412
+ preserving the ACL in the new key object will require two
413
+ additional API calls to S3, one to retrieve the current
414
+ ACL and one to set that ACL on the new object. If you
415
+ don't care about the ACL, a value of False will be
416
+ significantly more efficient.
417
+
418
+ :type encrypt_key: bool
419
+ :param encrypt_key: If True, the new copy of the object will
420
+ be encrypted on the server-side by S3 and will be stored
421
+ in an encrypted form while at rest in S3.
422
+
423
+ :type validate_dst_bucket: bool
424
+ :param validate_dst_bucket: If True, will validate the dst_bucket
425
+ by using an extra list request.
426
+
427
+ :rtype: :class:`boto.s3.key.Key` or subclass
428
+ :returns: An instance of the newly created key object
429
+ """
430
+ dst_bucket = self.bucket.connection.lookup(dst_bucket,
431
+ validate_dst_bucket)
432
+ if reduced_redundancy:
433
+ storage_class = 'REDUCED_REDUNDANCY'
434
+ else:
435
+ storage_class = self.storage_class
436
+ return dst_bucket.copy_key(dst_key, self.bucket.name,
437
+ self.name, metadata,
438
+ storage_class=storage_class,
439
+ preserve_acl=preserve_acl,
440
+ encrypt_key=encrypt_key)
441
+
442
+ def startElement(self, name, attrs, connection):
443
+ if name == 'Owner':
444
+ self.owner = User(self)
445
+ return self.owner
446
+ else:
447
+ return None
448
+
449
+ def endElement(self, name, value, connection):
450
+ if name == 'Key':
451
+ self.name = value
452
+ elif name == 'ETag':
453
+ self.etag = value
454
+ elif name == 'IsLatest':
455
+ if value == 'true':
456
+ self.is_latest = True
457
+ else:
458
+ self.is_latest = False
459
+ elif name == 'LastModified':
460
+ self.last_modified = value
461
+ elif name == 'Size':
462
+ self.size = int(value)
463
+ elif name == 'StorageClass':
464
+ self.storage_class = value
465
+ elif name == 'Owner':
466
+ pass
467
+ elif name == 'VersionId':
468
+ self.version_id = value
469
+ else:
470
+ setattr(self, name, value)
471
+
472
+ def exists(self):
473
+ """
474
+ Returns True if the key exists
475
+
476
+ :rtype: bool
477
+ :return: Whether the key exists on S3
478
+ """
479
+ return bool(self.bucket.lookup(self.name))
480
+
481
+ def delete(self):
482
+ """
483
+ Delete this key from S3
484
+ """
485
+ return self.bucket.delete_key(self.name, version_id=self.version_id)
486
+
487
+ def get_metadata(self, name):
488
+ return self.metadata.get(name)
489
+
490
+ def set_metadata(self, name, value):
491
+ self.metadata[name] = value
492
+
493
+ def update_metadata(self, d):
494
+ self.metadata.update(d)
495
+
496
+ # convenience methods for setting/getting ACL
497
+ def set_acl(self, acl_str, headers=None):
498
+ if self.bucket != None:
499
+ self.bucket.set_acl(acl_str, self.name, headers=headers)
500
+
501
+ def get_acl(self, headers=None):
502
+ if self.bucket != None:
503
+ return self.bucket.get_acl(self.name, headers=headers)
504
+
505
+ def get_xml_acl(self, headers=None):
506
+ if self.bucket != None:
507
+ return self.bucket.get_xml_acl(self.name, headers=headers)
508
+
509
+ def set_xml_acl(self, acl_str, headers=None):
510
+ if self.bucket != None:
511
+ return self.bucket.set_xml_acl(acl_str, self.name, headers=headers)
512
+
513
+ def set_canned_acl(self, acl_str, headers=None):
514
+ return self.bucket.set_canned_acl(acl_str, self.name, headers)
515
+
516
+ def get_redirect(self):
517
+ """Return the redirect location configured for this key.
518
+
519
+ If no redirect is configured (via set_redirect), then None
520
+ will be returned.
521
+
522
+ """
523
+ response = self.bucket.connection.make_request(
524
+ 'HEAD', self.bucket.name, self.name)
525
+ if response.status == 200:
526
+ return response.getheader('x-amz-website-redirect-location')
527
+ else:
528
+ raise self.provider.storage_response_error(
529
+ response.status, response.reason, response.read())
530
+
531
+ def set_redirect(self, redirect_location):
532
+ """Configure this key to redirect to another location.
533
+
534
+ When the bucket associated with this key is accessed from the website
535
+ endpoint, a 301 redirect will be issued to the specified
536
+ `redirect_location`.
537
+
538
+ :type redirect_location: string
539
+ :param redirect_location: The location to redirect.
540
+
541
+ """
542
+ headers = {'x-amz-website-redirect-location': redirect_location}
543
+ response = self.bucket.connection.make_request('PUT', self.bucket.name,
544
+ self.name, headers)
545
+ if response.status == 200:
546
+ return True
547
+ else:
548
+ raise self.provider.storage_response_error(
549
+ response.status, response.reason, response.read())
550
+
551
+ def make_public(self, headers=None):
552
+ return self.bucket.set_canned_acl('public-read', self.name, headers)
553
+
554
+ def generate_url(self, expires_in, method='GET', headers=None,
555
+ query_auth=True, force_http=False, response_headers=None,
556
+ expires_in_absolute=False, version_id=None,
557
+ policy=None, reduced_redundancy=False, encrypt_key=False):
558
+ """
559
+ Generate a URL to access this key.
560
+
561
+ :type expires_in: int
562
+ :param expires_in: How long the url is valid for, in seconds
563
+
564
+ :type method: string
565
+ :param method: The method to use for retrieving the file
566
+ (default is GET)
567
+
568
+ :type headers: dict
569
+ :param headers: Any headers to pass along in the request
570
+
571
+ :type query_auth: bool
572
+ :param query_auth:
573
+
574
+ :type force_http: bool
575
+ :param force_http: If True, http will be used instead of https.
576
+
577
+ :type response_headers: dict
578
+ :param response_headers: A dictionary containing HTTP
579
+ headers/values that will override any headers associated
580
+ with the stored object in the response. See
581
+ http://goo.gl/EWOPb for details.
582
+
583
+ :type expires_in_absolute: bool
584
+ :param expires_in_absolute:
585
+
586
+ :type version_id: string
587
+ :param version_id: The version_id of the object to GET. If specified
588
+ this overrides any value in the key.
589
+
590
+ :type policy: :class:`boto.s3.acl.CannedACLStrings`
591
+ :param policy: A canned ACL policy that will be applied to the
592
+ new key in S3.
593
+
594
+ :type reduced_redundancy: bool
595
+ :param reduced_redundancy: If True, this will set the storage
596
+ class of the new Key to be REDUCED_REDUNDANCY. The Reduced
597
+ Redundancy Storage (RRS) feature of S3, provides lower
598
+ redundancy at lower storage cost.
599
+
600
+ :type encrypt_key: bool
601
+ :param encrypt_key: If True, the new copy of the object will
602
+ be encrypted on the server-side by S3 and will be stored
603
+ in an encrypted form while at rest in S3.
604
+
605
+ :rtype: string
606
+ :return: The URL to access the key
607
+ """
608
+ provider = self.bucket.connection.provider
609
+ version_id = version_id or self.version_id
610
+ if headers is None:
611
+ headers = {}
612
+ else:
613
+ headers = headers.copy()
614
+
615
+ # add headers accordingly (usually PUT case)
616
+ if policy:
617
+ headers[provider.acl_header] = policy
618
+ if reduced_redundancy:
619
+ self.storage_class = 'REDUCED_REDUNDANCY'
620
+ if provider.storage_class_header:
621
+ headers[provider.storage_class_header] = self.storage_class
622
+ if encrypt_key:
623
+ headers[provider.server_side_encryption_header] = 'AES256'
624
+ headers = boto.utils.merge_meta(headers, self.metadata, provider)
625
+
626
+ return self.bucket.connection.generate_url(expires_in, method,
627
+ self.bucket.name, self.name,
628
+ headers, query_auth,
629
+ force_http,
630
+ response_headers,
631
+ expires_in_absolute,
632
+ version_id)
633
+
634
+ def send_file(self, fp, headers=None, cb=None, num_cb=10,
635
+ query_args=None, chunked_transfer=False, size=None):
636
+ """
637
+ Upload a file to a key into a bucket on S3.
638
+
639
+ :type fp: file
640
+ :param fp: The file pointer to upload. The file pointer must
641
+ point point at the offset from which you wish to upload.
642
+ ie. if uploading the full file, it should point at the
643
+ start of the file. Normally when a file is opened for
644
+ reading, the fp will point at the first byte. See the
645
+ bytes parameter below for more info.
646
+
647
+ :type headers: dict
648
+ :param headers: The headers to pass along with the PUT request
649
+
650
+ :type cb: function
651
+ :param cb: a callback function that will be called to report
652
+ progress on the upload. The callback should accept two
653
+ integer parameters, the first representing the number of
654
+ bytes that have been successfully transmitted to S3 and
655
+ the second representing the size of the to be transmitted
656
+ object.
657
+
658
+ :type num_cb: int
659
+ :param num_cb: (optional) If a callback is specified with the
660
+ cb parameter this parameter determines the granularity of
661
+ the callback by defining the maximum number of times the
662
+ callback will be called during the file
663
+ transfer. Providing a negative integer will cause your
664
+ callback to be called with each buffer read.
665
+
666
+ :type size: int
667
+ :param size: (optional) The Maximum number of bytes to read
668
+ from the file pointer (fp). This is useful when uploading
669
+ a file in multiple parts where you are splitting the file
670
+ up into different ranges to be uploaded. If not specified,
671
+ the default behaviour is to read all bytes from the file
672
+ pointer. Less bytes may be available.
673
+ """
674
+ provider = self.bucket.connection.provider
675
+ try:
676
+ spos = fp.tell()
677
+ except IOError:
678
+ spos = None
679
+ self.read_from_stream = False
680
+
681
+ def sender(http_conn, method, path, data, headers):
682
+ # This function is called repeatedly for temporary retries
683
+ # so we must be sure the file pointer is pointing at the
684
+ # start of the data.
685
+ if spos is not None and spos != fp.tell():
686
+ fp.seek(spos)
687
+ elif spos is None and self.read_from_stream:
688
+ # if seek is not supported, and we've read from this
689
+ # stream already, then we need to abort retries to
690
+ # avoid setting bad data.
691
+ raise provider.storage_data_error(
692
+ 'Cannot retry failed request. fp does not support seeking.')
693
+
694
+ http_conn.putrequest(method, path)
695
+ for key in headers:
696
+ http_conn.putheader(key, headers[key])
697
+ http_conn.endheaders()
698
+
699
+ # Calculate all MD5 checksums on the fly, if not already computed
700
+ if not self.base64md5:
701
+ m = md5()
702
+ else:
703
+ m = None
704
+
705
+ save_debug = self.bucket.connection.debug
706
+ self.bucket.connection.debug = 0
707
+ # If the debuglevel < 4 we don't want to show connection
708
+ # payload, so turn off HTTP connection-level debug output (to
709
+ # be restored below).
710
+ # Use the getattr approach to allow this to work in AppEngine.
711
+ if getattr(http_conn, 'debuglevel', 0) < 4:
712
+ http_conn.set_debuglevel(0)
713
+
714
+ data_len = 0
715
+ if cb:
716
+ if size:
717
+ cb_size = size
718
+ elif self.size:
719
+ cb_size = self.size
720
+ else:
721
+ cb_size = 0
722
+ if chunked_transfer and cb_size == 0:
723
+ # For chunked Transfer, we call the cb for every 1MB
724
+ # of data transferred, except when we know size.
725
+ cb_count = (1024 * 1024) / self.BufferSize
726
+ elif num_cb > 1:
727
+ cb_count = int(math.ceil(cb_size / self.BufferSize / (num_cb - 1.0)))
728
+ elif num_cb < 0:
729
+ cb_count = -1
730
+ else:
731
+ cb_count = 0
732
+ i = 0
733
+ cb(data_len, cb_size)
734
+
735
+ bytes_togo = size
736
+ if bytes_togo and bytes_togo < self.BufferSize:
737
+ chunk = fp.read(bytes_togo)
738
+ else:
739
+ chunk = fp.read(self.BufferSize)
740
+ if spos is None:
741
+ # read at least something from a non-seekable fp.
742
+ self.read_from_stream = True
743
+ while chunk:
744
+ chunk_len = len(chunk)
745
+ data_len += chunk_len
746
+ if chunked_transfer:
747
+ http_conn.send('%x;\r\n' % chunk_len)
748
+ http_conn.send(chunk)
749
+ http_conn.send('\r\n')
750
+ else:
751
+ http_conn.send(chunk)
752
+ if m:
753
+ m.update(chunk)
754
+ if bytes_togo:
755
+ bytes_togo -= chunk_len
756
+ if bytes_togo <= 0:
757
+ break
758
+ if cb:
759
+ i += 1
760
+ if i == cb_count or cb_count == -1:
761
+ cb(data_len, cb_size)
762
+ i = 0
763
+ if bytes_togo and bytes_togo < self.BufferSize:
764
+ chunk = fp.read(bytes_togo)
765
+ else:
766
+ chunk = fp.read(self.BufferSize)
767
+
768
+ self.size = data_len
769
+
770
+ if m:
771
+ # Use the chunked trailer for the digest
772
+ hd = m.hexdigest()
773
+ self.md5, self.base64md5 = self.get_md5_from_hexdigest(hd)
774
+
775
+ if chunked_transfer:
776
+ http_conn.send('0\r\n')
777
+ # http_conn.send("Content-MD5: %s\r\n" % self.base64md5)
778
+ http_conn.send('\r\n')
779
+
780
+ if cb and (cb_count <= 1 or i > 0) and data_len > 0:
781
+ cb(data_len, cb_size)
782
+
783
+ http_conn.set_debuglevel(save_debug)
784
+ self.bucket.connection.debug = save_debug
785
+ response = http_conn.getresponse()
786
+ body = response.read()
787
+ if ((response.status == 500 or response.status == 503 or
788
+ response.getheader('location')) and not chunked_transfer):
789
+ # we'll try again.
790
+ return response
791
+ elif response.status >= 200 and response.status <= 299:
792
+ self.etag = response.getheader('etag')
793
+ if self.etag != '"%s"' % self.md5:
794
+ raise provider.storage_data_error(
795
+ 'ETag from S3 did not match computed MD5')
796
+ return response
797
+ else:
798
+ raise provider.storage_response_error(
799
+ response.status, response.reason, body)
800
+
801
+ if not headers:
802
+ headers = {}
803
+ else:
804
+ headers = headers.copy()
805
+ headers['User-Agent'] = UserAgent
806
+ if self.storage_class != 'STANDARD':
807
+ headers[provider.storage_class_header] = self.storage_class
808
+ if 'Content-Encoding' in headers:
809
+ self.content_encoding = headers['Content-Encoding']
810
+ if 'Content-Language' in headers:
811
+ self.content_encoding = headers['Content-Language']
812
+ if 'Content-Type' in headers:
813
+ # Some use cases need to suppress sending of the Content-Type
814
+ # header and depend on the receiving server to set the content
815
+ # type. This can be achieved by setting headers['Content-Type']
816
+ # to None when calling this method.
817
+ if headers['Content-Type'] is None:
818
+ # Delete null Content-Type value to skip sending that header.
819
+ del headers['Content-Type']
820
+ else:
821
+ self.content_type = headers['Content-Type']
822
+ elif self.path:
823
+ self.content_type = mimetypes.guess_type(self.path)[0]
824
+ if self.content_type == None:
825
+ self.content_type = self.DefaultContentType
826
+ headers['Content-Type'] = self.content_type
827
+ else:
828
+ headers['Content-Type'] = self.content_type
829
+ if self.base64md5:
830
+ headers['Content-MD5'] = self.base64md5
831
+ if chunked_transfer:
832
+ headers['Transfer-Encoding'] = 'chunked'
833
+ #if not self.base64md5:
834
+ # headers['Trailer'] = "Content-MD5"
835
+ else:
836
+ headers['Content-Length'] = str(self.size)
837
+ headers['Expect'] = '100-Continue'
838
+ headers = boto.utils.merge_meta(headers, self.metadata, provider)
839
+ resp = self.bucket.connection.make_request('PUT', self.bucket.name,
840
+ self.name, headers,
841
+ sender=sender,
842
+ query_args=query_args)
843
+ self.handle_version_headers(resp, force=True)
844
+
845
+ def compute_md5(self, fp, size=None):
846
+ """
847
+ :type fp: file
848
+ :param fp: File pointer to the file to MD5 hash. The file
849
+ pointer will be reset to the same position before the
850
+ method returns.
851
+
852
+ :type size: int
853
+ :param size: (optional) The Maximum number of bytes to read
854
+ from the file pointer (fp). This is useful when uploading
855
+ a file in multiple parts where the file is being split
856
+ inplace into different parts. Less bytes may be available.
857
+
858
+ :rtype: tuple
859
+ :return: A tuple containing the hex digest version of the MD5
860
+ hash as the first element and the base64 encoded version
861
+ of the plain digest as the second element.
862
+ """
863
+ tup = compute_md5(fp, size=size)
864
+ # Returned values are MD5 hash, base64 encoded MD5 hash, and data size.
865
+ # The internal implementation of compute_md5() needs to return the
866
+ # data size but we don't want to return that value to the external
867
+ # caller because it changes the class interface (i.e. it might
868
+ # break some code) so we consume the third tuple value here and
869
+ # return the remainder of the tuple to the caller, thereby preserving
870
+ # the existing interface.
871
+ self.size = tup[2]
872
+ return tup[0:2]
873
+
874
+ def set_contents_from_stream(self, fp, headers=None, replace=True,
875
+ cb=None, num_cb=10, policy=None,
876
+ reduced_redundancy=False, query_args=None,
877
+ size=None):
878
+ """
879
+ Store an object using the name of the Key object as the key in
880
+ cloud and the contents of the data stream pointed to by 'fp' as
881
+ the contents.
882
+
883
+ The stream object is not seekable and total size is not known.
884
+ This has the implication that we can't specify the
885
+ Content-Size and Content-MD5 in the header. So for huge
886
+ uploads, the delay in calculating MD5 is avoided but with a
887
+ penalty of inability to verify the integrity of the uploaded
888
+ data.
889
+
890
+ :type fp: file
891
+ :param fp: the file whose contents are to be uploaded
892
+
893
+ :type headers: dict
894
+ :param headers: additional HTTP headers to be sent with the
895
+ PUT request.
896
+
897
+ :type replace: bool
898
+ :param replace: If this parameter is False, the method will first check
899
+ to see if an object exists in the bucket with the same key. If it
900
+ does, it won't overwrite it. The default value is True which will
901
+ overwrite the object.
902
+
903
+ :type cb: function
904
+ :param cb: a callback function that will be called to report
905
+ progress on the upload. The callback should accept two integer
906
+ parameters, the first representing the number of bytes that have
907
+ been successfully transmitted to GS and the second representing the
908
+ total number of bytes that need to be transmitted.
909
+
910
+ :type num_cb: int
911
+ :param num_cb: (optional) If a callback is specified with the
912
+ cb parameter, this parameter determines the granularity of
913
+ the callback by defining the maximum number of times the
914
+ callback will be called during the file transfer.
915
+
916
+ :type policy: :class:`boto.gs.acl.CannedACLStrings`
917
+ :param policy: A canned ACL policy that will be applied to the new key
918
+ in GS.
919
+
920
+ :type reduced_redundancy: bool
921
+ :param reduced_redundancy: If True, this will set the storage
922
+ class of the new Key to be REDUCED_REDUNDANCY. The Reduced
923
+ Redundancy Storage (RRS) feature of S3, provides lower
924
+ redundancy at lower storage cost.
925
+
926
+ :type size: int
927
+ :param size: (optional) The Maximum number of bytes to read from
928
+ the file pointer (fp). This is useful when uploading a
929
+ file in multiple parts where you are splitting the file up
930
+ into different ranges to be uploaded. If not specified,
931
+ the default behaviour is to read all bytes from the file
932
+ pointer. Less bytes may be available.
933
+ """
934
+
935
+ provider = self.bucket.connection.provider
936
+ if not provider.supports_chunked_transfer():
937
+ raise BotoClientError('%s does not support chunked transfer'
938
+ % provider.get_provider_name())
939
+
940
+ # Name of the Object should be specified explicitly for Streams.
941
+ if not self.name or self.name == '':
942
+ raise BotoClientError('Cannot determine the destination '
943
+ 'object name for the given stream')
944
+
945
+ if headers is None:
946
+ headers = {}
947
+ if policy:
948
+ headers[provider.acl_header] = policy
949
+
950
+ if reduced_redundancy:
951
+ self.storage_class = 'REDUCED_REDUNDANCY'
952
+ if provider.storage_class_header:
953
+ headers[provider.storage_class_header] = self.storage_class
954
+
955
+ if self.bucket != None:
956
+ if not replace:
957
+ if self.bucket.lookup(self.name):
958
+ return
959
+ self.send_file(fp, headers, cb, num_cb, query_args,
960
+ chunked_transfer=True, size=size)
961
+
962
+ def set_contents_from_file(self, fp, headers=None, replace=True,
963
+ cb=None, num_cb=10, policy=None, md5=None,
964
+ reduced_redundancy=False, query_args=None,
965
+ encrypt_key=False, size=None, rewind=False):
966
+ """
967
+ Store an object in S3 using the name of the Key object as the
968
+ key in S3 and the contents of the file pointed to by 'fp' as the
969
+ contents. The data is read from 'fp' from its current position until
970
+ 'size' bytes have been read or EOF.
971
+
972
+ :type fp: file
973
+ :param fp: the file whose contents to upload
974
+
975
+ :type headers: dict
976
+ :param headers: Additional HTTP headers that will be sent with
977
+ the PUT request.
978
+
979
+ :type replace: bool
980
+ :param replace: If this parameter is False, the method will
981
+ first check to see if an object exists in the bucket with
982
+ the same key. If it does, it won't overwrite it. The
983
+ default value is True which will overwrite the object.
984
+
985
+ :type cb: function
986
+ :param cb: a callback function that will be called to report
987
+ progress on the upload. The callback should accept two
988
+ integer parameters, the first representing the number of
989
+ bytes that have been successfully transmitted to S3 and
990
+ the second representing the size of the to be transmitted
991
+ object.
992
+
993
+ :type cb: int
994
+ :param num_cb: (optional) If a callback is specified with the
995
+ cb parameter this parameter determines the granularity of
996
+ the callback by defining the maximum number of times the
997
+ callback will be called during the file transfer.
998
+
999
+ :type policy: :class:`boto.s3.acl.CannedACLStrings`
1000
+ :param policy: A canned ACL policy that will be applied to the
1001
+ new key in S3.
1002
+
1003
+ :type md5: A tuple containing the hexdigest version of the MD5
1004
+ checksum of the file as the first element and the
1005
+ Base64-encoded version of the plain checksum as the second
1006
+ element. This is the same format returned by the
1007
+ compute_md5 method.
1008
+ :param md5: If you need to compute the MD5 for any reason
1009
+ prior to upload, it's silly to have to do it twice so this
1010
+ param, if present, will be used as the MD5 values of the
1011
+ file. Otherwise, the checksum will be computed.
1012
+
1013
+ :type reduced_redundancy: bool
1014
+ :param reduced_redundancy: If True, this will set the storage
1015
+ class of the new Key to be REDUCED_REDUNDANCY. The Reduced
1016
+ Redundancy Storage (RRS) feature of S3, provides lower
1017
+ redundancy at lower storage cost.
1018
+
1019
+ :type encrypt_key: bool
1020
+ :param encrypt_key: If True, the new copy of the object will
1021
+ be encrypted on the server-side by S3 and will be stored
1022
+ in an encrypted form while at rest in S3.
1023
+
1024
+ :type size: int
1025
+ :param size: (optional) The Maximum number of bytes to read
1026
+ from the file pointer (fp). This is useful when uploading
1027
+ a file in multiple parts where you are splitting the file
1028
+ up into different ranges to be uploaded. If not specified,
1029
+ the default behaviour is to read all bytes from the file
1030
+ pointer. Less bytes may be available.
1031
+
1032
+ :type rewind: bool
1033
+ :param rewind: (optional) If True, the file pointer (fp) will
1034
+ be rewound to the start before any bytes are read from
1035
+ it. The default behaviour is False which reads from the
1036
+ current position of the file pointer (fp).
1037
+
1038
+ :rtype: int
1039
+ :return: The number of bytes written to the key.
1040
+ """
1041
+ provider = self.bucket.connection.provider
1042
+ headers = headers or {}
1043
+ if policy:
1044
+ headers[provider.acl_header] = policy
1045
+ if encrypt_key:
1046
+ headers[provider.server_side_encryption_header] = 'AES256'
1047
+
1048
+ if rewind:
1049
+ # caller requests reading from beginning of fp.
1050
+ fp.seek(0, os.SEEK_SET)
1051
+ else:
1052
+ # The following seek/tell/seek logic is intended
1053
+ # to detect applications using the older interface to
1054
+ # set_contents_from_file(), which automatically rewound the
1055
+ # file each time the Key was reused. This changed with commit
1056
+ # 14ee2d03f4665fe20d19a85286f78d39d924237e, to support uploads
1057
+ # split into multiple parts and uploaded in parallel, and at
1058
+ # the time of that commit this check was added because otherwise
1059
+ # older programs would get a success status and upload an empty
1060
+ # object. Unfortuantely, it's very inefficient for fp's implemented
1061
+ # by KeyFile (used, for example, by gsutil when copying between
1062
+ # providers). So, we skip the check for the KeyFile case.
1063
+ # TODO: At some point consider removing this seek/tell/seek
1064
+ # logic, after enough time has passed that it's unlikely any
1065
+ # programs remain that assume the older auto-rewind interface.
1066
+ if not isinstance(fp, KeyFile):
1067
+ spos = fp.tell()
1068
+ fp.seek(0, os.SEEK_END)
1069
+ if fp.tell() == spos:
1070
+ fp.seek(0, os.SEEK_SET)
1071
+ if fp.tell() != spos:
1072
+ # Raise an exception as this is likely a programming
1073
+ # error whereby there is data before the fp but nothing
1074
+ # after it.
1075
+ fp.seek(spos)
1076
+ raise AttributeError('fp is at EOF. Use rewind option '
1077
+ 'or seek() to data start.')
1078
+ # seek back to the correct position.
1079
+ fp.seek(spos)
1080
+
1081
+ if reduced_redundancy:
1082
+ self.storage_class = 'REDUCED_REDUNDANCY'
1083
+ if provider.storage_class_header:
1084
+ headers[provider.storage_class_header] = self.storage_class
1085
+ # TODO - What if provider doesn't support reduced reduncancy?
1086
+ # What if different providers provide different classes?
1087
+ if hasattr(fp, 'name'):
1088
+ self.path = fp.name
1089
+ if self.bucket != None:
1090
+ if not md5 and provider.supports_chunked_transfer():
1091
+ # defer md5 calculation to on the fly and
1092
+ # we don't know anything about size yet.
1093
+ chunked_transfer = True
1094
+ self.size = None
1095
+ else:
1096
+ chunked_transfer = False
1097
+ if isinstance(fp, KeyFile):
1098
+ # Avoid EOF seek for KeyFile case as it's very inefficient.
1099
+ key = fp.getkey()
1100
+ size = key.size - fp.tell()
1101
+ self.size = size
1102
+ # At present both GCS and S3 use MD5 for the etag for
1103
+ # non-multipart-uploaded objects. If the etag is 32 hex
1104
+ # chars use it as an MD5, to avoid having to read the file
1105
+ # twice while transferring.
1106
+ if (re.match('^"[a-fA-F0-9]{32}"$', key.etag)):
1107
+ etag = key.etag.strip('"')
1108
+ md5 = (etag, base64.b64encode(binascii.unhexlify(etag)))
1109
+ if not md5:
1110
+ # compute_md5() and also set self.size to actual
1111
+ # size of the bytes read computing the md5.
1112
+ md5 = self.compute_md5(fp, size)
1113
+ # adjust size if required
1114
+ size = self.size
1115
+ elif size:
1116
+ self.size = size
1117
+ else:
1118
+ # If md5 is provided, still need to size so
1119
+ # calculate based on bytes to end of content
1120
+ spos = fp.tell()
1121
+ fp.seek(0, os.SEEK_END)
1122
+ self.size = fp.tell() - spos
1123
+ fp.seek(spos)
1124
+ size = self.size
1125
+ self.md5 = md5[0]
1126
+ self.base64md5 = md5[1]
1127
+
1128
+ if self.name == None:
1129
+ self.name = self.md5
1130
+ if not replace:
1131
+ if self.bucket.lookup(self.name):
1132
+ return
1133
+
1134
+ self.send_file(fp, headers=headers, cb=cb, num_cb=num_cb,
1135
+ query_args=query_args,
1136
+ chunked_transfer=chunked_transfer, size=size)
1137
+ # return number of bytes written.
1138
+ return self.size
1139
+
1140
+ def set_contents_from_filename(self, filename, headers=None, replace=True,
1141
+ cb=None, num_cb=10, policy=None, md5=None,
1142
+ reduced_redundancy=False,
1143
+ encrypt_key=False):
1144
+ """
1145
+ Store an object in S3 using the name of the Key object as the
1146
+ key in S3 and the contents of the file named by 'filename'.
1147
+ See set_contents_from_file method for details about the
1148
+ parameters.
1149
+
1150
+ :type filename: string
1151
+ :param filename: The name of the file that you want to put onto S3
1152
+
1153
+ :type headers: dict
1154
+ :param headers: Additional headers to pass along with the
1155
+ request to AWS.
1156
+
1157
+ :type replace: bool
1158
+ :param replace: If True, replaces the contents of the file
1159
+ if it already exists.
1160
+
1161
+ :type cb: function
1162
+ :param cb: a callback function that will be called to report
1163
+ progress on the upload. The callback should accept two
1164
+ integer parameters, the first representing the number of
1165
+ bytes that have been successfully transmitted to S3 and
1166
+ the second representing the size of the to be transmitted
1167
+ object.
1168
+
1169
+ :type cb: int
1170
+ :param num_cb: (optional) If a callback is specified with the
1171
+ cb parameter this parameter determines the granularity of
1172
+ the callback by defining the maximum number of times the
1173
+ callback will be called during the file transfer.
1174
+
1175
+ :type policy: :class:`boto.s3.acl.CannedACLStrings`
1176
+ :param policy: A canned ACL policy that will be applied to the
1177
+ new key in S3.
1178
+
1179
+ :type md5: A tuple containing the hexdigest version of the MD5
1180
+ checksum of the file as the first element and the
1181
+ Base64-encoded version of the plain checksum as the second
1182
+ element. This is the same format returned by the
1183
+ compute_md5 method.
1184
+ :param md5: If you need to compute the MD5 for any reason
1185
+ prior to upload, it's silly to have to do it twice so this
1186
+ param, if present, will be used as the MD5 values of the
1187
+ file. Otherwise, the checksum will be computed.
1188
+
1189
+ :type reduced_redundancy: bool
1190
+ :param reduced_redundancy: If True, this will set the storage
1191
+ class of the new Key to be REDUCED_REDUNDANCY. The Reduced
1192
+ Redundancy Storage (RRS) feature of S3, provides lower
1193
+ redundancy at lower storage cost. :type encrypt_key: bool
1194
+ :param encrypt_key: If True, the new copy of the object
1195
+ will be encrypted on the server-side by S3 and will be
1196
+ stored in an encrypted form while at rest in S3.
1197
+ """
1198
+ fp = open(filename, 'rb')
1199
+ try:
1200
+ self.set_contents_from_file(fp, headers, replace, cb, num_cb,
1201
+ policy, md5, reduced_redundancy,
1202
+ encrypt_key=encrypt_key)
1203
+ finally:
1204
+ fp.close()
1205
+
1206
+ def set_contents_from_string(self, s, headers=None, replace=True,
1207
+ cb=None, num_cb=10, policy=None, md5=None,
1208
+ reduced_redundancy=False,
1209
+ encrypt_key=False):
1210
+ """
1211
+ Store an object in S3 using the name of the Key object as the
1212
+ key in S3 and the string 's' as the contents.
1213
+ See set_contents_from_file method for details about the
1214
+ parameters.
1215
+
1216
+ :type headers: dict
1217
+ :param headers: Additional headers to pass along with the
1218
+ request to AWS.
1219
+
1220
+ :type replace: bool
1221
+ :param replace: If True, replaces the contents of the file if
1222
+ it already exists.
1223
+
1224
+ :type cb: function
1225
+ :param cb: a callback function that will be called to report
1226
+ progress on the upload. The callback should accept two
1227
+ integer parameters, the first representing the number of
1228
+ bytes that have been successfully transmitted to S3 and
1229
+ the second representing the size of the to be transmitted
1230
+ object.
1231
+
1232
+ :type cb: int
1233
+ :param num_cb: (optional) If a callback is specified with the
1234
+ cb parameter this parameter determines the granularity of
1235
+ the callback by defining the maximum number of times the
1236
+ callback will be called during the file transfer.
1237
+
1238
+ :type policy: :class:`boto.s3.acl.CannedACLStrings`
1239
+ :param policy: A canned ACL policy that will be applied to the
1240
+ new key in S3.
1241
+
1242
+ :type md5: A tuple containing the hexdigest version of the MD5
1243
+ checksum of the file as the first element and the
1244
+ Base64-encoded version of the plain checksum as the second
1245
+ element. This is the same format returned by the
1246
+ compute_md5 method.
1247
+ :param md5: If you need to compute the MD5 for any reason
1248
+ prior to upload, it's silly to have to do it twice so this
1249
+ param, if present, will be used as the MD5 values of the
1250
+ file. Otherwise, the checksum will be computed.
1251
+
1252
+ :type reduced_redundancy: bool
1253
+ :param reduced_redundancy: If True, this will set the storage
1254
+ class of the new Key to be REDUCED_REDUNDANCY. The Reduced
1255
+ Redundancy Storage (RRS) feature of S3, provides lower
1256
+ redundancy at lower storage cost.
1257
+
1258
+ :type encrypt_key: bool
1259
+ :param encrypt_key: If True, the new copy of the object will
1260
+ be encrypted on the server-side by S3 and will be stored
1261
+ in an encrypted form while at rest in S3.
1262
+ """
1263
+ if isinstance(s, unicode):
1264
+ s = s.encode("utf-8")
1265
+ fp = StringIO.StringIO(s)
1266
+ r = self.set_contents_from_file(fp, headers, replace, cb, num_cb,
1267
+ policy, md5, reduced_redundancy,
1268
+ encrypt_key=encrypt_key)
1269
+ fp.close()
1270
+ return r
1271
+
1272
+ def get_file(self, fp, headers=None, cb=None, num_cb=10,
1273
+ torrent=False, version_id=None, override_num_retries=None,
1274
+ response_headers=None):
1275
+ """
1276
+ Retrieves a file from an S3 Key
1277
+
1278
+ :type fp: file
1279
+ :param fp: File pointer to put the data into
1280
+
1281
+ :type headers: string
1282
+ :param: headers to send when retrieving the files
1283
+
1284
+ :type cb: function
1285
+ :param cb: a callback function that will be called to report
1286
+ progress on the upload. The callback should accept two
1287
+ integer parameters, the first representing the number of
1288
+ bytes that have been successfully transmitted to S3 and
1289
+ the second representing the size of the to be transmitted
1290
+ object.
1291
+
1292
+ :type cb: int
1293
+ :param num_cb: (optional) If a callback is specified with the
1294
+ cb parameter this parameter determines the granularity of
1295
+ the callback by defining the maximum number of times the
1296
+ callback will be called during the file transfer.
1297
+
1298
+ :type torrent: bool
1299
+ :param torrent: Flag for whether to get a torrent for the file
1300
+
1301
+ :type override_num_retries: int
1302
+ :param override_num_retries: If not None will override configured
1303
+ num_retries parameter for underlying GET.
1304
+
1305
+ :type response_headers: dict
1306
+ :param response_headers: A dictionary containing HTTP
1307
+ headers/values that will override any headers associated
1308
+ with the stored object in the response. See
1309
+ http://goo.gl/EWOPb for details.
1310
+ """
1311
+ self._get_file_internal(fp, headers=headers, cb=cb, num_cb=num_cb,
1312
+ torrent=torrent, version_id=version_id,
1313
+ override_num_retries=override_num_retries,
1314
+ response_headers=response_headers,
1315
+ query_args=None)
1316
+
1317
+ def _get_file_internal(self, fp, headers=None, cb=None, num_cb=10,
1318
+ torrent=False, version_id=None, override_num_retries=None,
1319
+ response_headers=None, query_args=None):
1320
+ if headers is None:
1321
+ headers = {}
1322
+ save_debug = self.bucket.connection.debug
1323
+ if self.bucket.connection.debug == 1:
1324
+ self.bucket.connection.debug = 0
1325
+
1326
+ query_args = query_args or []
1327
+ if torrent:
1328
+ query_args.append('torrent')
1329
+ m = None
1330
+ else:
1331
+ m = md5()
1332
+ # If a version_id is passed in, use that. If not, check to see
1333
+ # if the Key object has an explicit version_id and, if so, use that.
1334
+ # Otherwise, don't pass a version_id query param.
1335
+ if version_id is None:
1336
+ version_id = self.version_id
1337
+ if version_id:
1338
+ query_args.append('versionId=%s' % version_id)
1339
+ if response_headers:
1340
+ for key in response_headers:
1341
+ query_args.append('%s=%s' % (key, urllib.quote(response_headers[key])))
1342
+ query_args = '&'.join(query_args)
1343
+ self.open('r', headers, query_args=query_args,
1344
+ override_num_retries=override_num_retries)
1345
+
1346
+ data_len = 0
1347
+ if cb:
1348
+ if self.size is None:
1349
+ cb_size = 0
1350
+ else:
1351
+ cb_size = self.size
1352
+ if self.size is None and num_cb != -1:
1353
+ # If size is not available due to chunked transfer for example,
1354
+ # we'll call the cb for every 1MB of data transferred.
1355
+ cb_count = (1024 * 1024) / self.BufferSize
1356
+ elif num_cb > 1:
1357
+ cb_count = int(math.ceil(cb_size/self.BufferSize/(num_cb-1.0)))
1358
+ elif num_cb < 0:
1359
+ cb_count = -1
1360
+ else:
1361
+ cb_count = 0
1362
+ i = 0
1363
+ cb(data_len, cb_size)
1364
+ for bytes in self:
1365
+ fp.write(bytes)
1366
+ data_len += len(bytes)
1367
+ if m:
1368
+ m.update(bytes)
1369
+ if cb:
1370
+ if cb_size > 0 and data_len >= cb_size:
1371
+ break
1372
+ i += 1
1373
+ if i == cb_count or cb_count == -1:
1374
+ cb(data_len, cb_size)
1375
+ i = 0
1376
+ if cb and (cb_count <= 1 or i > 0) and data_len > 0:
1377
+ cb(data_len, cb_size)
1378
+ if m:
1379
+ self.md5 = m.hexdigest()
1380
+ if self.size is None and not torrent and "Range" not in headers:
1381
+ self.size = data_len
1382
+ self.close()
1383
+ self.bucket.connection.debug = save_debug
1384
+
1385
+ def get_torrent_file(self, fp, headers=None, cb=None, num_cb=10):
1386
+ """
1387
+ Get a torrent file (see to get_file)
1388
+
1389
+ :type fp: file
1390
+ :param fp: The file pointer of where to put the torrent
1391
+
1392
+ :type headers: dict
1393
+ :param headers: Headers to be passed
1394
+
1395
+ :type cb: function
1396
+ :param cb: a callback function that will be called to report
1397
+ progress on the upload. The callback should accept two
1398
+ integer parameters, the first representing the number of
1399
+ bytes that have been successfully transmitted to S3 and
1400
+ the second representing the size of the to be transmitted
1401
+ object.
1402
+
1403
+ :type cb: int
1404
+ :param num_cb: (optional) If a callback is specified with the
1405
+ cb parameter this parameter determines the granularity of
1406
+ the callback by defining the maximum number of times the
1407
+ callback will be called during the file transfer.
1408
+
1409
+ """
1410
+ return self.get_file(fp, headers, cb, num_cb, torrent=True)
1411
+
1412
+ def get_contents_to_file(self, fp, headers=None,
1413
+ cb=None, num_cb=10,
1414
+ torrent=False,
1415
+ version_id=None,
1416
+ res_download_handler=None,
1417
+ response_headers=None):
1418
+ """
1419
+ Retrieve an object from S3 using the name of the Key object as the
1420
+ key in S3. Write the contents of the object to the file pointed
1421
+ to by 'fp'.
1422
+
1423
+ :type fp: File -like object
1424
+ :param fp:
1425
+
1426
+ :type headers: dict
1427
+ :param headers: additional HTTP headers that will be sent with
1428
+ the GET request.
1429
+
1430
+ :type cb: function
1431
+ :param cb: a callback function that will be called to report
1432
+ progress on the upload. The callback should accept two
1433
+ integer parameters, the first representing the number of
1434
+ bytes that have been successfully transmitted to S3 and
1435
+ the second representing the size of the to be transmitted
1436
+ object.
1437
+
1438
+ :type cb: int
1439
+ :param num_cb: (optional) If a callback is specified with the
1440
+ cb parameter this parameter determines the granularity of
1441
+ the callback by defining the maximum number of times the
1442
+ callback will be called during the file transfer.
1443
+
1444
+ :type torrent: bool
1445
+ :param torrent: If True, returns the contents of a torrent
1446
+ file as a string.
1447
+
1448
+ :type res_upload_handler: ResumableDownloadHandler
1449
+ :param res_download_handler: If provided, this handler will
1450
+ perform the download.
1451
+
1452
+ :type response_headers: dict
1453
+ :param response_headers: A dictionary containing HTTP
1454
+ headers/values that will override any headers associated
1455
+ with the stored object in the response. See
1456
+ http://goo.gl/EWOPb for details.
1457
+ """
1458
+ if self.bucket != None:
1459
+ if res_download_handler:
1460
+ res_download_handler.get_file(self, fp, headers, cb, num_cb,
1461
+ torrent=torrent,
1462
+ version_id=version_id)
1463
+ else:
1464
+ self.get_file(fp, headers, cb, num_cb, torrent=torrent,
1465
+ version_id=version_id,
1466
+ response_headers=response_headers)
1467
+
1468
+ def get_contents_to_filename(self, filename, headers=None,
1469
+ cb=None, num_cb=10,
1470
+ torrent=False,
1471
+ version_id=None,
1472
+ res_download_handler=None,
1473
+ response_headers=None):
1474
+ """
1475
+ Retrieve an object from S3 using the name of the Key object as the
1476
+ key in S3. Store contents of the object to a file named by 'filename'.
1477
+ See get_contents_to_file method for details about the
1478
+ parameters.
1479
+
1480
+ :type filename: string
1481
+ :param filename: The filename of where to put the file contents
1482
+
1483
+ :type headers: dict
1484
+ :param headers: Any additional headers to send in the request
1485
+
1486
+ :type cb: function
1487
+ :param cb: a callback function that will be called to report
1488
+ progress on the upload. The callback should accept two
1489
+ integer parameters, the first representing the number of
1490
+ bytes that have been successfully transmitted to S3 and
1491
+ the second representing the size of the to be transmitted
1492
+ object.
1493
+
1494
+ :type cb: int
1495
+ :param num_cb: (optional) If a callback is specified with the
1496
+ cb parameter this parameter determines the granularity of
1497
+ the callback by defining the maximum number of times the
1498
+ callback will be called during the file transfer.
1499
+
1500
+ :type torrent: bool
1501
+ :param torrent: If True, returns the contents of a torrent file
1502
+ as a string.
1503
+
1504
+ :type res_upload_handler: ResumableDownloadHandler
1505
+ :param res_download_handler: If provided, this handler will
1506
+ perform the download.
1507
+
1508
+ :type response_headers: dict
1509
+ :param response_headers: A dictionary containing HTTP
1510
+ headers/values that will override any headers associated
1511
+ with the stored object in the response. See
1512
+ http://goo.gl/EWOPb for details.
1513
+ """
1514
+ fp = open(filename, 'wb')
1515
+ try:
1516
+ self.get_contents_to_file(fp, headers, cb, num_cb, torrent=torrent,
1517
+ version_id=version_id,
1518
+ res_download_handler=res_download_handler,
1519
+ response_headers=response_headers)
1520
+ except Exception:
1521
+ os.remove(filename)
1522
+ raise
1523
+ finally:
1524
+ fp.close()
1525
+ # if last_modified date was sent from s3, try to set file's timestamp
1526
+ if self.last_modified != None:
1527
+ try:
1528
+ modified_tuple = rfc822.parsedate_tz(self.last_modified)
1529
+ modified_stamp = int(rfc822.mktime_tz(modified_tuple))
1530
+ os.utime(fp.name, (modified_stamp, modified_stamp))
1531
+ except Exception:
1532
+ pass
1533
+
1534
+ def get_contents_as_string(self, headers=None,
1535
+ cb=None, num_cb=10,
1536
+ torrent=False,
1537
+ version_id=None,
1538
+ response_headers=None):
1539
+ """
1540
+ Retrieve an object from S3 using the name of the Key object as the
1541
+ key in S3. Return the contents of the object as a string.
1542
+ See get_contents_to_file method for details about the
1543
+ parameters.
1544
+
1545
+ :type headers: dict
1546
+ :param headers: Any additional headers to send in the request
1547
+
1548
+ :type cb: function
1549
+ :param cb: a callback function that will be called to report
1550
+ progress on the upload. The callback should accept two
1551
+ integer parameters, the first representing the number of
1552
+ bytes that have been successfully transmitted to S3 and
1553
+ the second representing the size of the to be transmitted
1554
+ object.
1555
+
1556
+ :type cb: int
1557
+ :param num_cb: (optional) If a callback is specified with the
1558
+ cb parameter this parameter determines the granularity of
1559
+ the callback by defining the maximum number of times the
1560
+ callback will be called during the file transfer.
1561
+
1562
+ :type torrent: bool
1563
+ :param torrent: If True, returns the contents of a torrent file
1564
+ as a string.
1565
+
1566
+ :type response_headers: dict
1567
+ :param response_headers: A dictionary containing HTTP
1568
+ headers/values that will override any headers associated
1569
+ with the stored object in the response. See
1570
+ http://goo.gl/EWOPb for details.
1571
+
1572
+ :rtype: string
1573
+ :returns: The contents of the file as a string
1574
+ """
1575
+ fp = StringIO.StringIO()
1576
+ self.get_contents_to_file(fp, headers, cb, num_cb, torrent=torrent,
1577
+ version_id=version_id,
1578
+ response_headers=response_headers)
1579
+ return fp.getvalue()
1580
+
1581
+ def add_email_grant(self, permission, email_address, headers=None):
1582
+ """
1583
+ Convenience method that provides a quick way to add an email grant
1584
+ to a key. This method retrieves the current ACL, creates a new
1585
+ grant based on the parameters passed in, adds that grant to the ACL
1586
+ and then PUT's the new ACL back to S3.
1587
+
1588
+ :type permission: string
1589
+ :param permission: The permission being granted. Should be one of:
1590
+ (READ, WRITE, READ_ACP, WRITE_ACP, FULL_CONTROL).
1591
+
1592
+ :type email_address: string
1593
+ :param email_address: The email address associated with the AWS
1594
+ account your are granting the permission to.
1595
+
1596
+ :type recursive: boolean
1597
+ :param recursive: A boolean value to controls whether the
1598
+ command will apply the grant to all keys within the bucket
1599
+ or not. The default value is False. By passing a True
1600
+ value, the call will iterate through all keys in the
1601
+ bucket and apply the same grant to each key. CAUTION: If
1602
+ you have a lot of keys, this could take a long time!
1603
+ """
1604
+ policy = self.get_acl(headers=headers)
1605
+ policy.acl.add_email_grant(permission, email_address)
1606
+ self.set_acl(policy, headers=headers)
1607
+
1608
+ def add_user_grant(self, permission, user_id, headers=None,
1609
+ display_name=None):
1610
+ """
1611
+ Convenience method that provides a quick way to add a canonical
1612
+ user grant to a key. This method retrieves the current ACL,
1613
+ creates a new grant based on the parameters passed in, adds that
1614
+ grant to the ACL and then PUT's the new ACL back to S3.
1615
+
1616
+ :type permission: string
1617
+ :param permission: The permission being granted. Should be one of:
1618
+ (READ, WRITE, READ_ACP, WRITE_ACP, FULL_CONTROL).
1619
+
1620
+ :type user_id: string
1621
+ :param user_id: The canonical user id associated with the AWS
1622
+ account your are granting the permission to.
1623
+
1624
+ :type display_name: string
1625
+ :param display_name: An option string containing the user's
1626
+ Display Name. Only required on Walrus.
1627
+ """
1628
+ policy = self.get_acl(headers=headers)
1629
+ policy.acl.add_user_grant(permission, user_id,
1630
+ display_name=display_name)
1631
+ self.set_acl(policy, headers=headers)
1632
+
1633
+ def _normalize_metadata(self, metadata):
1634
+ if type(metadata) == set:
1635
+ norm_metadata = set()
1636
+ for k in metadata:
1637
+ norm_metadata.add(k.lower())
1638
+ else:
1639
+ norm_metadata = {}
1640
+ for k in metadata:
1641
+ norm_metadata[k.lower()] = metadata[k]
1642
+ return norm_metadata
1643
+
1644
+ def _get_remote_metadata(self, headers=None):
1645
+ """
1646
+ Extracts metadata from existing URI into a dict, so we can
1647
+ overwrite/delete from it to form the new set of metadata to apply to a
1648
+ key.
1649
+ """
1650
+ metadata = {}
1651
+ for underscore_name in self._underscore_base_user_settable_fields:
1652
+ if hasattr(self, underscore_name):
1653
+ value = getattr(self, underscore_name)
1654
+ if value:
1655
+ # Generate HTTP field name corresponding to "_" named field.
1656
+ field_name = underscore_name.replace('_', '-')
1657
+ metadata[field_name.lower()] = value
1658
+ # self.metadata contains custom metadata, which are all user-settable.
1659
+ prefix = self.provider.metadata_prefix
1660
+ for underscore_name in self.metadata:
1661
+ field_name = underscore_name.replace('_', '-')
1662
+ metadata['%s%s' % (prefix, field_name.lower())] = (
1663
+ self.metadata[underscore_name])
1664
+ return metadata
1665
+
1666
+ def set_remote_metadata(self, metadata_plus, metadata_minus, preserve_acl,
1667
+ headers=None):
1668
+ metadata_plus = self._normalize_metadata(metadata_plus)
1669
+ metadata_minus = self._normalize_metadata(metadata_minus)
1670
+ metadata = self._get_remote_metadata()
1671
+ metadata.update(metadata_plus)
1672
+ for h in metadata_minus:
1673
+ if h in metadata:
1674
+ del metadata[h]
1675
+ src_bucket = self.bucket
1676
+ # Boto prepends the meta prefix when adding headers, so strip prefix in
1677
+ # metadata before sending back in to copy_key() call.
1678
+ rewritten_metadata = {}
1679
+ for h in metadata:
1680
+ if (h.startswith('x-goog-meta-') or h.startswith('x-amz-meta-')):
1681
+ rewritten_h = (h.replace('x-goog-meta-', '')
1682
+ .replace('x-amz-meta-', ''))
1683
+ else:
1684
+ rewritten_h = h
1685
+ rewritten_metadata[rewritten_h] = metadata[h]
1686
+ metadata = rewritten_metadata
1687
+ src_bucket.copy_key(self.name, self.bucket.name, self.name,
1688
+ metadata=metadata, preserve_acl=preserve_acl,
1689
+ headers=headers)
1690
+
1691
+ def restore(self, days, headers=None):
1692
+ """Restore an object from an archive.
1693
+
1694
+ :type days: int
1695
+ :param days: The lifetime of the restored object (must
1696
+ be at least 1 day). If the object is already restored
1697
+ then this parameter can be used to readjust the lifetime
1698
+ of the restored object. In this case, the days
1699
+ param is with respect to the initial time of the request.
1700
+ If the object has not been restored, this param is with
1701
+ respect to the completion time of the request.
1702
+
1703
+ """
1704
+ response = self.bucket.connection.make_request(
1705
+ 'POST', self.bucket.name, self.name,
1706
+ data=self.RestoreBody % days,
1707
+ headers=headers, query_args='restore')
1708
+ if response.status not in (200, 202):
1709
+ provider = self.bucket.connection.provider
1710
+ raise provider.storage_response_error(response.status,
1711
+ response.reason,
1712
+ response.read())