ec50b5a7 |
## Amazon S3 manager
## Author: Michal Ludvig <michal@logix.cz>
## http://www.logix.cz/michal
## License: GPL Version 2
|
b6e1cada |
import logging |
f06cf98f |
from logging import debug, info, warning, error |
b6e1cada |
import re |
2d7ceec9 |
import Progress |
fa664913 |
from SortedDict import SortedDict |
b6e1cada |
|
b008e471 |
class Config(object):
_instance = None
_parsed_files = [] |
0d91ff3f |
_doc = {} |
b008e471 |
access_key = ""
secret_key = "" |
dc758146 |
host_base = "s3.amazonaws.com"
host_bucket = "%(bucket)s.s3.amazonaws.com" |
d2b144df |
simpledb_host = "sdb.amazonaws.com" |
b3488bab |
cloudfront_host = "cloudfront.amazonaws.com" |
b020ea02 |
cloudfront_resource = "/2010-06-01/distribution" |
b008e471 |
verbosity = logging.WARNING |
2d7ceec9 |
progress_meter = True |
4396d217 |
progress_class = Progress.ProgressCR |
b008e471 |
send_chunk = 4096
recv_chunk = 4096 |
8567b8ed |
list_md5 = False |
b008e471 |
human_readable_sizes = False |
dc1c96cf |
extra_headers = SortedDict(ignore_case = True) |
b008e471 |
force = False |
cb0bbaef |
enable = None |
9197e62e |
get_continue = False |
559c963f |
skip_existing = False |
7406fc6c |
recursive = False |
99b416bc |
acl_public = None
acl_grants = []
acl_revokes = [] |
afe194f8 |
proxy_host = "" |
d35b41f4 |
proxy_port = 3128 |
8ec1807f |
encrypt = False |
a368faf1 |
dry_run = False
preserve_attrs = True
preserve_attrs_list = [
'uname', # Verbose owner Name (e.g. 'root') |
bc4c306d |
'uid', # Numeric user ID (e.g. 0) |
a368faf1 |
'gname', # Group name (e.g. 'users') |
bc4c306d |
'gid', # Numeric group ID (e.g. 100)
'atime', # Last access timestamp |
a368faf1 |
'mtime', # Modification timestamp
'ctime', # Creation timestamp
'mode', # File mode (e.g. rwxr-xr-x = 755)
#'acl', # Full ACL (not yet supported)
] |
0d91ff3f |
delete_removed = False
_doc['delete_removed'] = "[sync] Remove remote S3 objects when local file has been deleted" |
8ec1807f |
gpg_passphrase = "" |
49731b40 |
gpg_command = "" |
8ec1807f |
gpg_encrypt = "%(gpg_command)s -c --verbose --no-use-agent --batch --yes --passphrase-fd %(passphrase_fd)s -o %(output_file)s %(input_file)s"
gpg_decrypt = "%(gpg_command)s -d --verbose --no-use-agent --batch --yes --passphrase-fd %(passphrase_fd)s -o %(output_file)s %(input_file)s" |
d35b41f4 |
use_https = False |
dc758146 |
bucket_location = "US" |
eb31131e |
default_mime_type = "binary/octet-stream" |
39b813d5 |
guess_mime_type = True |
227fabf8 |
# List of checks to be performed for 'sync'
sync_checks = ['size', 'md5'] # 'weak-timestamp' |
d5e87cdf |
# List of compiled REGEXPs |
711318eb |
exclude = [] |
227fabf8 |
include = [] |
d5e87cdf |
# Dict mapping compiled REGEXPs back to their textual form
debug_exclude = {} |
227fabf8 |
debug_include = {} |
82d9eafa |
encoding = "utf-8" |
3c07424d |
urlencoding_mode = "normal" |
cb0bbaef |
log_target_prefix = "" |
a7ea0bee |
reduced_redundancy = False |
7b5df262 |
follow_symlinks=False |
b008e471 |
## Creating a singleton
def __new__(self, configfile = None):
if self._instance is None:
self._instance = object.__new__(self)
return self._instance
def __init__(self, configfile = None):
if configfile:
self.read_config_file(configfile)
def option_list(self):
retval = []
for option in dir(self):
## Skip attributes that start with underscore or are not string, int or bool
option_type = type(getattr(Config, option))
if option.startswith("_") or \
not (option_type in (
type("string"), # str
type(42), # int
type(True))): # bool
continue
retval.append(option)
return retval
def read_config_file(self, configfile):
cp = ConfigParser(configfile)
for option in self.option_list():
self.update_option(option, cp.get(option))
self._parsed_files.append(configfile)
|
5a736f08 |
def dump_config(self, stream):
ConfigDumper(stream).dump("default", self)
|
b008e471 |
def update_option(self, option, value):
if value is None:
return
#### Special treatment of some options
## verbosity must be known to "logging" module
if option == "verbosity":
try:
setattr(Config, "verbosity", logging._levelNames[value])
except KeyError:
error("Config: verbosity level '%s' is not valid" % value)
## allow yes/no, true/false, on/off and 1/0 for boolean options
elif type(getattr(Config, option)) is type(True): # bool
if str(value).lower() in ("true", "yes", "on", "1"):
setattr(Config, option, True)
elif str(value).lower() in ("false", "no", "off", "0"):
setattr(Config, option, False)
else:
error("Config: value of option '%s' must be Yes or No, not '%s'" % (option, value))
elif type(getattr(Config, option)) is type(42): # int
try:
setattr(Config, option, int(value))
except ValueError, e:
error("Config: value of option '%s' must be an integer, not '%s'" % (option, value))
else: # string
setattr(Config, option, value)
|
5a736f08 |
class ConfigParser(object): |
b6e1cada |
def __init__(self, file, sections = []):
self.cfg = {}
self.parse_file(file, sections)
def parse_file(self, file, sections = []): |
59864e57 |
debug("ConfigParser: Reading file '%s'" % file) |
b6e1cada |
if type(sections) != type([]):
sections = [sections]
in_our_section = True
f = open(file, "r")
r_comment = re.compile("^\s*#.*")
r_empty = re.compile("^\s*$")
r_section = re.compile("^\[([^\]]+)\]")
r_data = re.compile("^\s*(?P<key>\w+)\s*=\s*(?P<value>.*)")
r_quotes = re.compile("^\"(.*)\"\s*$")
for line in f:
if r_comment.match(line) or r_empty.match(line):
continue
is_section = r_section.match(line)
if is_section:
section = is_section.groups()[0]
in_our_section = (section in sections) or (len(sections) == 0)
continue
is_data = r_data.match(line)
if is_data and in_our_section:
data = is_data.groupdict()
if r_quotes.match(data["value"]):
data["value"] = data["value"][1:-1]
self.__setitem__(data["key"], data["value"]) |
8ec1807f |
if data["key"] in ("access_key", "secret_key", "gpg_passphrase"):
print_value = (data["value"][:2]+"...%d_chars..."+data["value"][-1:]) % (len(data["value"]) - 3) |
c72a850f |
else:
print_value = data["value"]
debug("ConfigParser: %s->%s" % (data["key"], print_value)) |
b6e1cada |
continue |
f06cf98f |
warning("Ignoring invalid line in '%s': %s" % (file, line)) |
b6e1cada |
def __getitem__(self, name):
return self.cfg[name]
def __setitem__(self, name, value):
self.cfg[name] = value
def get(self, name, default = None):
if self.cfg.has_key(name):
return self.cfg[name]
return default |
5a736f08 |
class ConfigDumper(object):
def __init__(self, stream):
self.stream = stream
def dump(self, section, config):
self.stream.write("[%s]\n" % section)
for option in config.option_list():
self.stream.write("%s = %s\n" % (option, getattr(config, option)))
|