git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3cmd/trunk@223 830e0280-6d2a-0410-9c65-932aecc39d9d
Michal Ludvig authored on 2008/09/03 10:48:55... | ... |
@@ -1,5 +1,13 @@ |
1 | 1 |
2008-09-01 Michal Ludvig <michal@logix.cz> |
2 | 2 |
|
3 |
+ * s3cmd, S3/Config.py: [rb] Allow removal of non-empty buckets |
|
4 |
+ with --force. |
|
5 |
+ [mb, rb] Allow multiple arguments, i.e. create or remove |
|
6 |
+ multiple buckets at once. |
|
7 |
+ [del] Perform recursive removal with --recursive (or -r). |
|
8 |
+ |
|
9 |
+2008-09-01 Michal Ludvig <michal@logix.cz> |
|
10 |
+ |
|
3 | 11 |
* s3cmd: Refuse 'sync' together with '--encrypt'. |
4 | 12 |
* S3/S3.py: removed object_{get,put,delete}_uri() functions |
5 | 13 |
and made object_{get,put,delete}() accept URI instead of |
... | ... |
@@ -125,34 +125,43 @@ def subcmd_bucket_list(s3, uri): |
125 | 125 |
)) |
126 | 126 |
|
127 | 127 |
def cmd_bucket_create(args): |
128 |
- uri = S3Uri(args[0]) |
|
129 |
- if not uri.type == "s3" or not uri.has_bucket() or uri.has_object(): |
|
130 |
- raise ParameterError("Expecting S3 URI with just the bucket name set instead of '%s'" % args[0]) |
|
131 |
- try: |
|
132 |
- s3 = S3(Config()) |
|
133 |
- response = s3.bucket_create(uri.bucket(), cfg.bucket_location) |
|
134 |
- except S3Error, e: |
|
135 |
- if S3.codes.has_key(e.info["Code"]): |
|
136 |
- error(S3.codes[e.info["Code"]] % uri.bucket()) |
|
137 |
- return |
|
138 |
- else: |
|
139 |
- raise |
|
140 |
- output("Bucket '%s' created" % uri.bucket()) |
|
128 |
+ s3 = S3(Config()) |
|
129 |
+ for arg in args: |
|
130 |
+ uri = S3Uri(arg) |
|
131 |
+ if not uri.type == "s3" or not uri.has_bucket() or uri.has_object(): |
|
132 |
+ raise ParameterError("Expecting S3 URI with just the bucket name set instead of '%s'" % arg) |
|
133 |
+ try: |
|
134 |
+ response = s3.bucket_create(uri.bucket(), cfg.bucket_location) |
|
135 |
+ output("Bucket '%s' created" % uri.uri()) |
|
136 |
+ except S3Error, e: |
|
137 |
+ if S3.codes.has_key(e.info["Code"]): |
|
138 |
+ error(S3.codes[e.info["Code"]] % uri.bucket()) |
|
139 |
+ return |
|
140 |
+ else: |
|
141 |
+ raise |
|
141 | 142 |
|
142 | 143 |
def cmd_bucket_delete(args): |
143 |
- uri = S3Uri(args[0]) |
|
144 |
- if not uri.type == "s3" or not uri.has_bucket() or uri.has_object(): |
|
145 |
- raise ParameterError("Expecting S3 URI with just the bucket name set instead of '%s'" % args[0]) |
|
146 |
- try: |
|
147 |
- s3 = S3(Config()) |
|
148 |
- response = s3.bucket_delete(uri.bucket()) |
|
149 |
- except S3Error, e: |
|
150 |
- if S3.codes.has_key(e.info["Code"]): |
|
151 |
- error(S3.codes[e.info["Code"]] % uri.bucket()) |
|
152 |
- return |
|
153 |
- else: |
|
154 |
- raise |
|
155 |
- output("Bucket '%s' removed" % uri.bucket()) |
|
144 |
+ def _bucket_delete_one(uri): |
|
145 |
+ try: |
|
146 |
+ response = s3.bucket_delete(uri.bucket()) |
|
147 |
+ except S3Error, e: |
|
148 |
+ if e.info['Code'] == 'BucketNotEmpty' and (cfg.force or cfg.recursive): |
|
149 |
+ warning("Bucket is not empty. Removing all the objects from it first. This may take some time...") |
|
150 |
+ subcmd_object_del_uri(uri, recursive = True) |
|
151 |
+ return _bucket_delete_one(uri) |
|
152 |
+ elif S3.codes.has_key(e.info["Code"]): |
|
153 |
+ error(S3.codes[e.info["Code"]] % uri.bucket()) |
|
154 |
+ return |
|
155 |
+ else: |
|
156 |
+ raise |
|
157 |
+ |
|
158 |
+ s3 = S3(Config()) |
|
159 |
+ for arg in args: |
|
160 |
+ uri = S3Uri(arg) |
|
161 |
+ if not uri.type == "s3" or not uri.has_bucket() or uri.has_object(): |
|
162 |
+ raise ParameterError("Expecting S3 URI with just the bucket name set instead of '%s'" % arg) |
|
163 |
+ _bucket_delete_one(uri) |
|
164 |
+ output("Bucket '%s' removed" % uri.uri()) |
|
156 | 165 |
|
157 | 166 |
def cmd_object_put(args): |
158 | 167 |
s3 = S3(Config()) |
... | ... |
@@ -260,16 +269,31 @@ def cmd_object_get(args): |
260 | 260 |
(uri, destination, response["size"], response["elapsed"], speed_fmt[0], speed_fmt[1])) |
261 | 261 |
|
262 | 262 |
def cmd_object_del(args): |
263 |
- s3 = S3(Config()) |
|
264 |
- |
|
265 | 263 |
while (len(args)): |
266 | 264 |
uri_arg = args.pop(0) |
267 | 265 |
uri = S3Uri(uri_arg) |
268 | 266 |
if uri.type != "s3" or not uri.has_object(): |
269 | 267 |
raise ParameterError("Expecting S3 URI instead of '%s'" % uri_arg) |
270 | 268 |
|
271 |
- response = s3.object_delete(uri) |
|
272 |
- output("Object %s deleted" % uri) |
|
269 |
+ subcmd_object_del_uri(uri) |
|
270 |
+ |
|
271 |
+def subcmd_object_del_uri(uri, recursive = None): |
|
272 |
+ s3 = S3(Config()) |
|
273 |
+ if recursive is None: |
|
274 |
+ recursive = cfg.recursive |
|
275 |
+ uri_list = [] |
|
276 |
+ if recursive: |
|
277 |
+ filelist = _get_filelist_remote(uri) |
|
278 |
+ uri_base = 's3://' + uri.bucket() + "/" |
|
279 |
+ for idx in filelist: |
|
280 |
+ object = filelist[idx] |
|
281 |
+ debug("Adding URI " + uri_base + object['object_key']) |
|
282 |
+ uri_list.append(S3Uri(uri_base + object['object_key'])) |
|
283 |
+ else: |
|
284 |
+ uri_list.append(uri) |
|
285 |
+ for _uri in uri_list: |
|
286 |
+ response = s3.object_delete(_uri) |
|
287 |
+ info("Object %s deleted" % _uri) |
|
273 | 288 |
|
274 | 289 |
def cmd_info(args): |
275 | 290 |
s3 = S3(Config()) |
... | ... |
@@ -885,6 +909,7 @@ def main(): |
885 | 885 |
optparser.add_option("-e", "--encrypt", dest="encrypt", action="store_true", help="Encrypt files before uploading to S3.") |
886 | 886 |
optparser.add_option( "--no-encrypt", dest="encrypt", action="store_false", help="Don't encrypt files.") |
887 | 887 |
optparser.add_option("-f", "--force", dest="force", action="store_true", help="Force overwrite and other dangerous operations.") |
888 |
+ optparser.add_option("-r", "--recursive", dest="recursive", action="store_true", help="Recursive upload, download or removal.") |
|
888 | 889 |
optparser.add_option("-P", "--acl-public", dest="acl_public", action="store_true", help="Store objects with ACL allowing read for anyone.") |
889 | 890 |
optparser.add_option( "--acl-private", dest="acl_public", action="store_false", help="Store objects with default ACL allowing access for you only.") |
890 | 891 |
optparser.add_option( "--delete-removed", dest="delete_removed", action="store_true", help="Delete remote objects with no corresponding local file [sync]") |