Browse code

Added ConfigParser Improved setting logging levels It can now quite reliably list buckets and objects

git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3py/trunk@37 830e0280-6d2a-0410-9c65-932aecc39d9d

Michal Ludvig authored on 2007/01/10 21:05:51
Showing 3 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,51 @@
0
+import logging
1
+from logging import debug, info, warn, error
2
+import re
3
+
4
+class ConfigParser:
5
+	def __init__(self, file, sections = []):
6
+		self.cfg = {}
7
+		self.parse_file(file, sections)
8
+	
9
+	def parse_file(self, file, sections = []):
10
+		if type(sections) != type([]):
11
+			sections = [sections]
12
+		in_our_section = True
13
+		f = open(file, "r")
14
+		r_comment = re.compile("^\s*#.*")
15
+		r_empty = re.compile("^\s*$")
16
+		r_section = re.compile("^\[([^\]]+)\]")
17
+		r_data = re.compile("^\s*(?P<key>\w+)\s*=\s*(?P<value>.*)")
18
+		r_quotes = re.compile("^\"(.*)\"\s*$")
19
+		for line in f:
20
+			if r_comment.match(line) or r_empty.match(line):
21
+				continue
22
+			is_section = r_section.match(line)
23
+			if is_section:
24
+				section = is_section.groups()[0]
25
+				in_our_section = (section in sections) or (len(sections) == 0)
26
+				continue
27
+			is_data = r_data.match(line)
28
+			if is_data and in_our_section:
29
+				data = is_data.groupdict()
30
+				if r_quotes.match(data["value"]):
31
+					data["value"] = data["value"][1:-1]
32
+				debug("ConfigParser: %s->%s" % (data["key"], data["value"]))
33
+				self.__setitem__(data["key"], data["value"])
34
+				continue
35
+
36
+	def __getitem__(self, name):
37
+		return self.cfg[name]
38
+	
39
+	def __setitem__(self, name, value):
40
+		self.cfg[name] = value
41
+	
42
+	def get(self, name, default = None):
43
+		if self.cfg.has_key(name):
44
+			return self.cfg[name]
45
+		return default
46
+
47
+if __name__ == "__main__":
48
+	logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s')
49
+	parser = ConfigParser("/home/mludvig/.s3cfg")
50
+	print parser["access_key"]
... ...
@@ -2,6 +2,7 @@
2 2
 
3 3
 import httplib2
4 4
 import sys
5
+import os
5 6
 import logging
6 7
 import time
7 8
 import base64
... ...
@@ -17,12 +18,28 @@ import elementtree.ElementTree as ET
17 17
 from utils import *
18 18
 from SortedDict import SortedDict
19 19
 from BidirMap import BidirMap
20
+from ConfigParser import ConfigParser
20 21
 
21 22
 class AwsConfig:
22
-	access_key = "<Put Your Access Key Here>"
23
-	secret_key = "<Put Your Secret Key Here>"
23
+	access_key = ""
24
+	secret_key = ""
24 25
 	host = "s3.amazonaws.com"
25
-	verbose = False
26
+	verbosity = logging.WARNING
27
+
28
+	def __init__(self, configfile = None):
29
+		if configfile:
30
+			self.read_config_file(configfile)
31
+
32
+	def read_config_file(self, configfile):
33
+		cp = ConfigParser(configfile)
34
+		AwsConfig.access_key = cp.get("access_key", AwsConfig.access_key)
35
+		AwsConfig.secret_key = cp.get("secret_key", AwsConfig.secret_key)
36
+		AwsConfig.host = cp.get("host", AwsConfig.host)
37
+		verbosity = cp.get("verbosity", "WARNING")
38
+		try:
39
+			AwsConfig.verbosity = logging._levelNames[verbosity]
40
+		except KeyError:
41
+			error("AwsConfig: verbosity level '%s' is not valid" % verbosity)
26 42
 
27 43
 class S3Error (Exception):
28 44
 	def __init__(self, response):
... ...
@@ -72,11 +89,13 @@ class S3:
72 72
 	def list_all_buckets(self):
73 73
 		request = self.create_request("LIST_ALL_BUCKETS")
74 74
 		response = self.send_request(request)
75
+		response["list"] = getListFromXml(response["data"], "Bucket")
75 76
 		return response
76 77
 	
77 78
 	def bucket_list(self, bucket):
78 79
 		request = self.create_request("BUCKET_LIST", bucket = bucket)
79 80
 		response = self.send_request(request)
81
+		response["list"] = getListFromXml(response["data"], "Contents")
80 82
 		return response
81 83
 
82 84
 	def create_request(self, operation, bucket = None, object = None, headers = None):
... ...
@@ -131,15 +150,12 @@ class S3:
131 131
 def cmd_buckets_list_all(args):
132 132
 	s3 = S3(AwsConfig())
133 133
 	response = s3.list_all_buckets()
134
-	tree = ET.fromstring(response["data"])
135
-	xmlns = getNameSpace(tree)
136
-	nodes = tree.findall('.//%sBucket' % xmlns)
137
-	buckets = parseNodes(nodes, xmlns)
134
+
138 135
 	maxlen = 0
139
-	for bucket in buckets:
136
+	for bucket in response["list"]:
140 137
 		if len(bucket["Name"]) > maxlen:
141 138
 			maxlen = len(bucket["Name"])
142
-	for bucket in buckets:
139
+	for bucket in response["list"]:
143 140
 		print "%s  %s" % (
144 141
 			formatDateTime(bucket["CreationDate"]),
145 142
 			bucket["Name"].ljust(maxlen),
... ...
@@ -151,20 +167,20 @@ def cmd_bucket_list(args):
151 151
 	try:
152 152
 		response = s3.bucket_list(bucket)
153 153
 	except S3Error, e:
154
-		if e.Code == "NoSuchBucket":
155
-			error("Bucket '%s' does not exist" % bucket)
154
+		codes = {
155
+			"NoSuchBucket" : "Bucket '%s' does not exist",
156
+			"AccessDenied" : "Access to bucket '%s' was denied",
157
+			}
158
+		if codes.has_key(e.Code):
159
+			error(codes[e.Code] % bucket)
156 160
 			return
157 161
 		else:
158 162
 			raise
159
-	tree = ET.fromstring(response["data"])
160
-	xmlns = getNameSpace(tree)
161
-	nodes = tree.findall('.//%sContents' % xmlns)
162
-	objects = parseNodes(nodes, xmlns)
163 163
 	maxlen = 0
164
-	for object in objects:
164
+	for object in response["list"]:
165 165
 		if len(object["Key"]) > maxlen:
166 166
 			maxlen = len(object["Key"])
167
-	for object in objects:
167
+	for object in response["list"]:
168 168
 		size, size_coeff = formatSize(object["Size"], True)
169 169
 		print "%s  %s%s  %s" % (
170 170
 			formatDateTime(object["LastModified"]),
... ...
@@ -174,33 +190,54 @@ def cmd_bucket_list(args):
174 174
 
175 175
 
176 176
 commands = {
177
-	"la" : ("List all buckets", cmd_buckets_list_all),
178
-	"lb" : ("List objects in bucket", cmd_bucket_list),
179
-#	"cb" : ("Create bucket", cmd_bucket_create),
180
-#	"rb" : ("Remove bucket", cmd_bucket_remove)
177
+	"la" : ("List all buckets", cmd_buckets_list_all, 0),
178
+	"lb" : ("List objects in bucket", cmd_bucket_list, 1),
179
+#	"cb" : ("Create bucket", cmd_bucket_create, 1),
180
+#	"rb" : ("Remove bucket", cmd_bucket_remove, 1)
181 181
 	}
182 182
 
183 183
 if __name__ == '__main__':
184
-	logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s')
185
-
186 184
 	optparser = OptionParser()
187
-	optparser.set_defaults(config="~/.s3fs.cfg")
185
+	optparser.set_defaults(config=os.getenv("HOME")+"/.s3cfg")
188 186
 	optparser.add_option("-c", "--config", dest="config", metavar="FILE", help="Config file name")
189
-	optparser.add_option("-d", "--debug", action="store_false", help="Enable debug output")
190
-	optparser.add_option("-v", "--verbose", action="store_false", help="Enable verbose output")
187
+	optparser.add_option("-d", "--debug", action="store_true", help="Enable debug output")
191 188
 	(options, args) = optparser.parse_args()
192 189
 
190
+	## Some mucking with logging levels to enable 
191
+	## debugging output for config file parser on request
192
+	init_logging_level = logging.INFO
193
+	if options.debug: init_logging_level = logging.DEBUG
194
+	logging.basicConfig(level=init_logging_level, format='%(levelname)s: %(message)s')
195
+	
196
+	## Now finally parse the config file
197
+	AwsConfig(options.config)
198
+
199
+	## And again some logging level adjustments, argh.
200
+	if options.debug:
201
+		AwsConfig.verbosity = logging.DEBUG
202
+	logging.root.setLevel(AwsConfig.verbosity)
203
+
193 204
 	if len(args) < 1:
194 205
 		error("Missing command. Please run with --help for more information.")
195 206
 		exit(1)
196 207
 
197
-	command = args[0]
198
-	args.remove(command)
208
+	command = args.pop(0)
199 209
 	try:
200
-		print commands[command][0]
201
-		commands[command][1](args)
210
+		debug("Command: " + commands[command][0])
211
+		## We must do this lookup in extra step to 
212
+		## avoid catching all KeyError exceptions
213
+		## from inner functions here. 
214
+		cmd_func = commands[command][1]
202 215
 	except KeyError, e:
203 216
 		error("Invalid command: %s" % e)
217
+		exit(1)
218
+
219
+	if len(args) < commands[command][2]:
220
+		error("Not enough paramters for command '%s'" % command)
221
+		exit(1)
222
+
223
+	try:
224
+		cmd_func(args)
204 225
 	except S3Error, e:
205 226
 		error("S3 error: " + str(e))
206 227
 
... ...
@@ -1,5 +1,6 @@
1 1
 import time
2 2
 import re
3
+import elementtree.ElementTree as ET
3 4
 
4 5
 def parseNodes(nodes, xmlns = ""):
5 6
 	retval = []
... ...
@@ -25,6 +26,12 @@ def getNameSpace(element):
25 25
 		return ""
26 26
 	return re.compile("^(\{[^}]+\})").match(element.tag).groups()[0]
27 27
 
28
+def getListFromXml(xml, node):
29
+	tree = ET.fromstring(xml)
30
+	xmlns = getNameSpace(tree)
31
+	nodes = tree.findall('.//%s%s' % (xmlns, node))
32
+	return parseNodes(nodes, xmlns)
33
+	
28 34
 def dateS3toPython(date):
29 35
 	date = re.compile("\.\d\d\dZ").sub(".000Z", date)
30 36
 	return time.strptime(date, "%Y-%m-%dT%H:%M:%S.000Z")