git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3py/trunk@50 830e0280-6d2a-0410-9c65-932aecc39d9d
Michal Ludvig authored on 2007/01/17 08:14:35... | ... |
@@ -153,7 +153,7 @@ class S3: |
153 | 153 |
|
154 | 154 |
def bucket_list(self, bucket, prefix = None): |
155 | 155 |
## TODO: use prefix if supplied |
156 |
- request = self.create_request("BUCKET_LIST", bucket = bucket) |
|
156 |
+ request = self.create_request("BUCKET_LIST", bucket = bucket, prefix = prefix) |
|
157 | 157 |
response = self.send_request(request) |
158 | 158 |
debug(response) |
159 | 159 |
response["list"] = getListFromXml(response["data"], "Contents") |
... | ... |
@@ -202,7 +202,7 @@ class S3: |
202 | 202 |
response = self.send_request(request) |
203 | 203 |
return response |
204 | 204 |
|
205 |
- def create_request(self, operation, bucket = None, object = None, headers = None): |
|
205 |
+ def create_request(self, operation, bucket = None, object = None, headers = None, **params): |
|
206 | 206 |
resource = "/" |
207 | 207 |
if bucket: |
208 | 208 |
resource += str(bucket) |
... | ... |
@@ -223,6 +223,13 @@ class S3: |
223 | 223 |
method_string = S3.http_methods.getkey(S3.operations[operation] & S3.http_methods["MASK"]) |
224 | 224 |
signature = self.sign_headers(method_string, resource, headers) |
225 | 225 |
headers["Authorization"] = "AWS "+self.config.access_key+":"+signature |
226 |
+ param_str = "" |
|
227 |
+ for param in params: |
|
228 |
+ if params[param] not in (None, ""): |
|
229 |
+ param_str += "&%s=%s" % (param, params[param]) |
|
230 |
+ if param_str != "": |
|
231 |
+ resource += "?" + param_str[1:] |
|
232 |
+ debug("CreateRequest: resource=" + resource) |
|
226 | 233 |
return (method_string, resource, headers) |
227 | 234 |
|
228 | 235 |
def send_request(self, request): |
... | ... |
@@ -322,6 +329,7 @@ class S3: |
322 | 322 |
if header.startswith("x-amz-"): |
323 | 323 |
h += header+":"+str(headers[header])+"\n" |
324 | 324 |
h += resource |
325 |
+ debug("SignHeaders: " + repr(h)) |
|
325 | 326 |
return base64.encodestring(hmac.new(self.config.secret_key, h, hashlib.sha1).digest()).strip() |
326 | 327 |
|
327 | 328 |
def check_bucket_name(self, bucket): |
... | ... |
@@ -10,7 +10,7 @@ import logging |
10 | 10 |
import time |
11 | 11 |
|
12 | 12 |
from copy import copy |
13 |
-from optparse import OptionParser, Option, OptionValueError |
|
13 |
+from optparse import OptionParser, Option, OptionValueError, IndentedHelpFormatter |
|
14 | 14 |
from logging import debug, info, warning, error |
15 | 15 |
import elementtree.ElementTree as ET |
16 | 16 |
|
... | ... |
@@ -56,8 +56,10 @@ def cmd_bucket_list(args): |
56 | 56 |
if not isuri: |
57 | 57 |
bucket = args[0] |
58 | 58 |
output("Bucket '%s':" % bucket) |
59 |
+ if object.endswith('*'): |
|
60 |
+ object = object[:-1] |
|
59 | 61 |
try: |
60 |
- response = s3.bucket_list(bucket) |
|
62 |
+ response = s3.bucket_list(bucket, prefix = object) |
|
61 | 63 |
except S3Error, e: |
62 | 64 |
if S3.codes.has_key(e.Code): |
63 | 65 |
error(S3.codes[e.Code] % bucket) |
... | ... |
@@ -102,6 +104,9 @@ def cmd_bucket_delete(args): |
102 | 102 |
raise |
103 | 103 |
output("Bucket '%s' removed" % bucket) |
104 | 104 |
|
105 |
+def cmd_cp(args): |
|
106 |
+ raise ParameterError("Not yet implemented") |
|
107 |
+ |
|
105 | 108 |
def cmd_object_put(args): |
106 | 109 |
s3 = S3(Config()) |
107 | 110 |
|
... | ... |
@@ -156,15 +161,22 @@ def cmd_object_del(args): |
156 | 156 |
output("Object %s deleted" % s3uri) |
157 | 157 |
|
158 | 158 |
commands = { |
159 |
- "mb" : ("Make bucket", cmd_bucket_create, 1), |
|
160 |
- "rb" : ("Remove bucket", cmd_bucket_delete, 1), |
|
161 |
- "ls" : ("List objects or buckets", cmd_ls, 0), |
|
162 |
- "la" : ("List all object in all buckets", cmd_buckets_list_all_all, 0), |
|
163 |
- "put": ("Put file into bucket", cmd_object_put, 2), |
|
164 |
- "get": ("Get file from bucket", cmd_object_get, 1), |
|
165 |
- "del": ("Delete file from bucket", cmd_object_del, 1), |
|
159 |
+ "mb" : ("Make bucket", "s3://BUCKET", cmd_bucket_create, 1), |
|
160 |
+ "rb" : ("Remove bucket", "s3://BUCKET", cmd_bucket_delete, 1), |
|
161 |
+ "ls" : ("List objects or buckets", "[s3://BUCKET[/PREFIX]]", cmd_ls, 0), |
|
162 |
+ "la" : ("List all object in all buckets", "", cmd_buckets_list_all_all, 0), |
|
163 |
+ "cp" : ("Copy files to / from S3 bucket", "SRC DST", cmd_cp, 2), |
|
164 |
+ "put": ("Put file into bucket", "FILE [FILE...] s3://BUCKET[/PREFIX]", cmd_object_put, 2), |
|
165 |
+ "get": ("Get file from bucket", "s3://BUCKET/OBJECT LOCAL_FILE", cmd_object_get, 1), |
|
166 |
+ "del": ("Delete file from bucket", "s3://BUCKET/OBJECT", cmd_object_del, 1), |
|
166 | 167 |
} |
167 | 168 |
|
169 |
+def format_commands(progname): |
|
170 |
+ help = "Commands:\n" |
|
171 |
+ for cmd in commands: |
|
172 |
+ help += " %s\n %s %s %s\n" % (commands[cmd][0], progname, cmd, commands[cmd][1]) |
|
173 |
+ return help |
|
174 |
+ |
|
168 | 175 |
class OptionMimeType(Option): |
169 | 176 |
def check_mimetype(option, opt, value): |
170 | 177 |
if re.compile("^[a-z0-9]+/[a-z0-9+\.-]+$", re.IGNORECASE).match(value): |
... | ... |
@@ -175,13 +187,20 @@ class OptionMimeType(Option): |
175 | 175 |
TYPE_CHECKER = copy(Option.TYPE_CHECKER) |
176 | 176 |
TYPE_CHECKER["mimetype"] = check_mimetype |
177 | 177 |
|
178 |
+class MyHelpFormatter(IndentedHelpFormatter): |
|
179 |
+ def format_epilog(self, epilog): |
|
180 |
+ if epilog: |
|
181 |
+ return "\n" + epilog + "\n" |
|
182 |
+ else: |
|
183 |
+ return "" |
|
184 |
+ |
|
178 | 185 |
if __name__ == '__main__': |
179 | 186 |
if float("%d.%d" %(sys.version_info[0], sys.version_info[1])) < 2.5: |
180 | 187 |
sys.stderr.write("ERROR: Python 2.5 or higher required, sorry.\n") |
181 | 188 |
exit(1) |
182 | 189 |
|
183 | 190 |
default_verbosity = Config().verbosity |
184 |
- optparser = OptionParser(option_class=OptionMimeType) |
|
191 |
+ optparser = OptionParser(option_class=OptionMimeType, formatter=MyHelpFormatter()) |
|
185 | 192 |
#optparser.disable_interspersed_args() |
186 | 193 |
optparser.set_defaults(config=os.getenv("HOME")+"/.s3cfg") |
187 | 194 |
optparser.add_option("-c", "--config", dest="config", metavar="FILE", help="Config file name. Defaults to %default") |
... | ... |
@@ -195,6 +214,9 @@ if __name__ == '__main__': |
195 | 195 |
optparser.add_option("-m", "--mime-type", dest="default_mime_type", type="mimetype", metavar="MIME/TYPE", help="Default MIME-type to be set for objects stored.") |
196 | 196 |
optparser.add_option("-M", "--guess-mime-type", dest="guess_mime_type", action="store_true", help="Guess MIME-type of files by their extension. Falls back to default MIME-Type as specified by --mime-type option") |
197 | 197 |
|
198 |
+ optparser.set_usage(optparser.usage + " COMMAND [parameters]") |
|
199 |
+ optparser.set_description("""S3cmd is a tool to manage objects in Amazon S3 storage. It allows for making and removing "buckets" and uploading, downloading and removing "objects" from these buckets.""") |
|
200 |
+ optparser.epilog = format_commands(optparser.get_prog_name()) |
|
198 | 201 |
(options, args) = optparser.parse_args() |
199 | 202 |
|
200 | 203 |
## Some mucking with logging levels to enable |
... | ... |
@@ -230,12 +252,12 @@ if __name__ == '__main__': |
230 | 230 |
## We must do this lookup in extra step to |
231 | 231 |
## avoid catching all KeyError exceptions |
232 | 232 |
## from inner functions. |
233 |
- cmd_func = commands[command][1] |
|
233 |
+ cmd_func = commands[command][2] |
|
234 | 234 |
except KeyError, e: |
235 | 235 |
error("Invalid command: %s" % e) |
236 | 236 |
exit(1) |
237 | 237 |
|
238 |
- if len(args) < commands[command][2]: |
|
238 |
+ if len(args) < commands[command][3]: |
|
239 | 239 |
error("Not enough paramters for command '%s'" % command) |
240 | 240 |
exit(1) |
241 | 241 |
|