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:511 | 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") |