Browse code

- Use prefix for listings if specified. - List all commands in --help

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
Showing 2 changed files
... ...
@@ -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