git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3py/trunk@55 830e0280-6d2a-0410-9c65-932aecc39d9d
Michal Ludvig authored on 2007/01/19 09:20:14... | ... |
@@ -46,6 +46,9 @@ class Config(object): |
46 | 46 |
self.update_option(option, cp.get(option)) |
47 | 47 |
self._parsed_files.append(configfile) |
48 | 48 |
|
49 |
+ def dump_config(self, stream): |
|
50 |
+ ConfigDumper(stream).dump("default", self) |
|
51 |
+ |
|
49 | 52 |
def update_option(self, option, value): |
50 | 53 |
if value is None: |
51 | 54 |
return |
... | ... |
@@ -72,7 +75,7 @@ class Config(object): |
72 | 72 |
else: # string |
73 | 73 |
setattr(Config, option, value) |
74 | 74 |
|
75 |
-class ConfigParser: |
|
75 |
+class ConfigParser(object): |
|
76 | 76 |
def __init__(self, file, sections = []): |
77 | 77 |
self.cfg = {} |
78 | 78 |
self.parse_file(file, sections) |
... | ... |
@@ -116,3 +119,13 @@ class ConfigParser: |
116 | 116 |
if self.cfg.has_key(name): |
117 | 117 |
return self.cfg[name] |
118 | 118 |
return default |
119 |
+ |
|
120 |
+class ConfigDumper(object): |
|
121 |
+ def __init__(self, stream): |
|
122 |
+ self.stream = stream |
|
123 |
+ |
|
124 |
+ def dump(self, section, config): |
|
125 |
+ self.stream.write("[%s]\n" % section) |
|
126 |
+ for option in config.option_list(): |
|
127 |
+ self.stream.write("%s = %s\n" % (option, getattr(config, option))) |
|
128 |
+ |
... | ... |
@@ -161,21 +161,66 @@ def cmd_object_del(args): |
161 | 161 |
response = s3.object_delete(bucket, object) |
162 | 162 |
output("Object %s deleted" % s3uri) |
163 | 163 |
|
164 |
-commands = { |
|
165 |
- "mb" : ("Make bucket", "s3://BUCKET", cmd_bucket_create, 1), |
|
166 |
- "rb" : ("Remove bucket", "s3://BUCKET", cmd_bucket_delete, 1), |
|
167 |
- "ls" : ("List objects or buckets", "[s3://BUCKET[/PREFIX]]", cmd_ls, 0), |
|
168 |
- "la" : ("List all object in all buckets", "", cmd_buckets_list_all_all, 0), |
|
169 |
- "cp" : ("Copy files to / from S3 bucket", "SRC DST", cmd_cp, 2), |
|
170 |
- "put": ("Put file into bucket", "FILE [FILE...] s3://BUCKET[/PREFIX]", cmd_object_put, 2), |
|
171 |
- "get": ("Get file from bucket", "s3://BUCKET/OBJECT LOCAL_FILE", cmd_object_get, 1), |
|
172 |
- "del": ("Delete file from bucket", "s3://BUCKET/OBJECT", cmd_object_del, 1), |
|
173 |
- } |
|
164 |
+def run_configure(config_file): |
|
165 |
+ cfg = Config() |
|
166 |
+ options = [ |
|
167 |
+ ("access_key", "Access Key"), |
|
168 |
+ ("secret_key", "Secret Key"), |
|
169 |
+ ] |
|
170 |
+ try: |
|
171 |
+ while 1: |
|
172 |
+ output("\nEnter new values or accept defaults in brackets with Enter.") |
|
173 |
+ output("Refer to user manual for detailed description of all options.\n") |
|
174 |
+ for option in options: |
|
175 |
+ prompt = option[1] |
|
176 |
+ try: |
|
177 |
+ val = getattr(cfg, option[0]) |
|
178 |
+ if val not in (None, ""): |
|
179 |
+ prompt += " [%s]" % val |
|
180 |
+ except AttributeError: |
|
181 |
+ pass |
|
182 |
+ |
|
183 |
+ if len(option) >= 3: |
|
184 |
+ output("%s" % option[2]) |
|
185 |
+ |
|
186 |
+ val = raw_input(prompt + ": ") |
|
187 |
+ if val != "": |
|
188 |
+ setattr(cfg, option[0], val) |
|
189 |
+ output("\nNew settings:") |
|
190 |
+ for option in options: |
|
191 |
+ output(" %s: %s" % (option[1], getattr(cfg, option[0]))) |
|
192 |
+ val = raw_input("\nChange any setting? [y/N] ") |
|
193 |
+ if not val.lower().startswith("y"): |
|
194 |
+ break |
|
195 |
+ f = open(config_file, "w") |
|
196 |
+ cfg.dump_config(f) |
|
197 |
+ f.close() |
|
198 |
+ output("Configuration saved to '%s'" % config_file) |
|
199 |
+ |
|
200 |
+ except (EOFError, KeyboardInterrupt): |
|
201 |
+ output("\nConfiguration aborted. Changes were NOT saved.") |
|
202 |
+ return |
|
203 |
+ |
|
204 |
+ except IOError, e: |
|
205 |
+ error("Writing config file failed: %s: %s" % (config_file, e.strerror)) |
|
206 |
+ exit(1) |
|
207 |
+ |
|
208 |
+commands = {} |
|
209 |
+commands_list = [ |
|
210 |
+ {"cmd":"mb", "label":"Make bucket", "param":"s3://BUCKET", "func":cmd_bucket_create, "argc":1}, |
|
211 |
+ {"cmd":"rb", "label":"Remove bucket", "param":"s3://BUCKET", "func":cmd_bucket_delete, "argc":1}, |
|
212 |
+ {"cmd":"ls", "label":"List objects or buckets", "param":"[s3://BUCKET[/PREFIX]]", "func":cmd_ls, "argc":0}, |
|
213 |
+ {"cmd":"la", "label":"List all object in all buckets", "param":"", "func":cmd_buckets_list_all_all, "argc":0}, |
|
214 |
+ {"cmd":"cp", "label":"Copy files to / from S3 bucket", "param":"SRC DST", "func":cmd_cp, "argc":2}, |
|
215 |
+ {"cmd":"put", "label":"Put file into bucket", "param":"FILE [FILE...] s3://BUCKET[/PREFIX]", "func":cmd_object_put, "argc":2}, |
|
216 |
+ {"cmd":"get", "label":"Get file from bucket", "param":"s3://BUCKET/OBJECT LOCAL_FILE", "func":cmd_object_get, "argc":1}, |
|
217 |
+ {"cmd":"del", "label":"Delete file from bucket", "param":"s3://BUCKET/OBJECT", "func":cmd_object_del, "argc":1}, |
|
218 |
+ ] |
|
174 | 219 |
|
175 | 220 |
def format_commands(progname): |
176 | 221 |
help = "Commands:\n" |
177 |
- for cmd in commands: |
|
178 |
- help += " %s\n %s %s %s\n" % (commands[cmd][0], progname, cmd, commands[cmd][1]) |
|
222 |
+ for cmd in commands_list: |
|
223 |
+ help += " %s\n %s %s %s\n" % (cmd["label"], progname, cmd["cmd"], cmd["param"]) |
|
179 | 224 |
return help |
180 | 225 |
|
181 | 226 |
class OptionMimeType(Option): |
... | ... |
@@ -200,6 +245,11 @@ if __name__ == '__main__': |
200 | 200 |
sys.stderr.write("ERROR: Python 2.5 or higher required, sorry.\n") |
201 | 201 |
exit(1) |
202 | 202 |
|
203 |
+ ## Populate "commands" from "commands_list" |
|
204 |
+ for cmd in commands_list: |
|
205 |
+ if cmd.has_key("cmd"): |
|
206 |
+ commands[cmd["cmd"]] = cmd |
|
207 |
+ |
|
203 | 208 |
default_verbosity = Config().verbosity |
204 | 209 |
optparser = OptionParser(option_class=OptionMimeType, formatter=MyHelpFormatter()) |
205 | 210 |
#optparser.disable_interspersed_args() |
... | ... |
@@ -214,6 +264,8 @@ if __name__ == '__main__': |
214 | 214 |
optparser.add_option("-P", "--acl-public", dest="acl_public", action="store_true", help="Store objects with ACL allowing read by anyone.") |
215 | 215 |
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.") |
216 | 216 |
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") |
217 |
+ optparser.add_option( "--dump-config", dest="dump_config", action="store_true", help="Dump current configuration after parsin config files and command line options and exit.") |
|
218 |
+ optparser.add_option( "--configure", dest="run_configure", action="store_true", help="Invoke interactive (re)configuration tool.") |
|
217 | 219 |
|
218 | 220 |
optparser.set_usage(optparser.usage + " COMMAND [parameters]") |
219 | 221 |
optparser.set_description('S3cmd is a tool to manage objects in '+ |
... | ... |
@@ -230,23 +282,40 @@ if __name__ == '__main__': |
230 | 230 |
logging.basicConfig(level=options.verbosity, format='%(levelname)s: %(message)s') |
231 | 231 |
|
232 | 232 |
## Now finally parse the config file |
233 |
- Config(options.config) |
|
233 |
+ try: |
|
234 |
+ cfg = Config(options.config) |
|
235 |
+ except IOError, e: |
|
236 |
+ if options.run_configure: |
|
237 |
+ cfg = Config() |
|
238 |
+ else: |
|
239 |
+ error("%s: %s" % (options.config, e.strerror)) |
|
240 |
+ error("Configuration file not available.") |
|
241 |
+ error("Consider using --configure parameter to create one.") |
|
242 |
+ exit(1) |
|
234 | 243 |
|
235 | 244 |
## And again some logging level adjustments |
236 | 245 |
## according to configfile and command line parameters |
237 | 246 |
if options.verbosity != default_verbosity: |
238 |
- Config().verbosity = options.verbosity |
|
239 |
- logging.root.setLevel(Config().verbosity) |
|
247 |
+ cfg.verbosity = options.verbosity |
|
248 |
+ logging.root.setLevel(cfg.verbosity) |
|
240 | 249 |
|
241 | 250 |
## Update Config with other parameters |
242 |
- for parameter in ( |
|
243 |
- "human_readable_sizes", |
|
244 |
- "force", |
|
245 |
- "show_uri", |
|
246 |
- "acl_public",): |
|
247 |
- if getattr(options, parameter) != None: |
|
248 |
- debug("Updating %s -> %s" % (parameter, getattr(options, parameter))) |
|
249 |
- setattr(Config, parameter, getattr(options, parameter)) |
|
251 |
+ for option in cfg.option_list(): |
|
252 |
+ try: |
|
253 |
+ if getattr(options, option) != None: |
|
254 |
+ debug("Updating %s -> %s" % (option, getattr(options, option))) |
|
255 |
+ cfg.update_option(option, getattr(options, option)) |
|
256 |
+ except AttributeError: |
|
257 |
+ ## Some Config() options are not settable from command line |
|
258 |
+ pass |
|
259 |
+ |
|
260 |
+ if options.dump_config: |
|
261 |
+ cfg.dump_config(sys.stdout) |
|
262 |
+ exit(0) |
|
263 |
+ |
|
264 |
+ if options.run_configure: |
|
265 |
+ run_configure(options.config) |
|
266 |
+ exit(0) |
|
250 | 267 |
|
251 | 268 |
if len(args) < 1: |
252 | 269 |
error("Missing command. Please run with --help for more information.") |
... | ... |
@@ -254,16 +323,16 @@ if __name__ == '__main__': |
254 | 254 |
|
255 | 255 |
command = args.pop(0) |
256 | 256 |
try: |
257 |
- debug("Command: " + commands[command][0]) |
|
257 |
+ debug("Command: " + commands[command]["cmd"]) |
|
258 | 258 |
## We must do this lookup in extra step to |
259 | 259 |
## avoid catching all KeyError exceptions |
260 | 260 |
## from inner functions. |
261 |
- cmd_func = commands[command][2] |
|
261 |
+ cmd_func = commands[command]["func"] |
|
262 | 262 |
except KeyError, e: |
263 | 263 |
error("Invalid command: %s" % e) |
264 | 264 |
exit(1) |
265 | 265 |
|
266 |
- if len(args) < commands[command][3]: |
|
266 |
+ if len(args) < commands[command]["argc"]: |
|
267 | 267 |
error("Not enough paramters for command '%s'" % command) |
268 | 268 |
exit(1) |
269 | 269 |
|