Commit 8be11e4a authored by Guido van Rossum's avatar Guido van Rossum

New options class, using zdoptions.py.

parent 298631a7
...@@ -22,8 +22,8 @@ Options: ...@@ -22,8 +22,8 @@ Options:
(a PATH must contain at least one "/") (a PATH must contain at least one "/")
-f/--filename FILENAME -- filename for FileStorage -f/--filename FILENAME -- filename for FileStorage
-h/--help -- print this usage message and exit -h/--help -- print this usage message and exit
-m/--monitor ADDRESS -- address of monitor server -m/--monitor ADDRESS -- address of monitor server ([HOST:]PORT or PATH)
-r/--record -- path of file to record low-level network activity -r/--record FILENAME -- filename to record low-level network activity
Unless -C is specified, -a and -f are required. Unless -C is specified, -a and -f are required.
""" """
...@@ -32,187 +32,33 @@ Unless -C is specified, -a and -f are required. ...@@ -32,187 +32,33 @@ Unless -C is specified, -a and -f are required.
# For the forseeable future, it must work under Python 2.1 as well as # For the forseeable future, it must work under Python 2.1 as well as
# 2.2 and above. # 2.2 and above.
# XXX The option parsing infrastructure could be shared with zdaemon.py
import os import os
import sys import sys
import getopt import getopt
import signal import signal
import socket import socket
import ZConfig, ZConfig.datatypes
import zLOG import zLOG
import ZConfig from zdaemon.zdoptions import ZDOptions
import ZEO
class Options:
"""A class to parse and hold the command line options.
Options are represented by various attributes (zeoport etc.).
Positional arguments are represented by the args attribute.
This also has a public usage() method that can be used to report
errors related to the command line.
"""
configuration = None
rootconf = None
args = []
def __init__(self, args=None, progname=None, doc=None):
"""Constructor.
Optional arguments:
args -- the command line arguments, less the program name
(default is sys.argv[1:] at the time of call)
progname -- the program name (default sys.argv[0])
doc -- usage message (default, __main__.__doc__)
"""
if args is None:
args = sys.argv[1:]
if progname is None:
progname = sys.argv[0]
self.progname = progname
if doc is None:
import __main__
doc = __main__.__doc__
if doc and not doc.endswith("\n"):
doc += "\n"
self.doc = doc
try:
self.options, self.args = getopt.getopt(args,
self._short_options,
self._long_options)
except getopt.error, msg:
self.usage(str(msg))
for opt, arg in self.options:
self.handle_option(opt, arg)
self.check_options()
# Default set of options. Subclasses should override.
_short_options = "C:h"
_long_options = ["configuration=", "help"]
def handle_option(self, opt, arg):
"""Handle one option. Subclasses should override.
This sets the various instance variables overriding the defaults.
When -h is detected, print the module docstring to stdout and exit(0).
"""
if opt in ("-C", "--configuration"):
self.set_configuration(arg)
if opt in ("-h", "--help"):
self.help()
def set_configuration(self, arg): def parse_address(arg):
self.configuration = arg # XXX Unclear whether this is an official part of the ZConfig API
obj = ZConfig.datatypes.SocketAddress(arg)
return obj.family, obj.address
def check_options(self): class ZEOOptions(ZDOptions):
"""Check options. Subclasses may override.
This can be used to ensure certain options are set, etc. storages = None
"""
self.load_configuration()
def load_schema(self): def handle_address(self, arg):
here = os.path.dirname(ZEO.__file__) self.family, self.address = parse_address(arg)
schemafile = os.path.join(here, "schema.xml")
self.schema = ZConfig.loadSchema(schemafile)
def load_configuration(self): def handle_monitor_address(self, arg):
if not self.configuration: self.monitor_family, self.monitor_address = parse_address(arg)
return
self.load_schema()
try:
self.rootconf, nil = ZConfig.loadConfig(self.schema,
self.configuration)
except ZConfig.ConfigurationError, errobj:
self.usage(str(errobj))
def help(self):
"""Print a long help message (self.doc) to stdout and exit(0).
Occurrences of "%s" in self.doc are replaced by self.progname. def handle_filename(self, arg):
""" from ZODB.config import FileStorage # That's a FileStorage *opener*!
doc = self.doc
if doc.find("%s") > 0:
doc = doc.replace("%s", self.progname)
print doc
sys.exit(0)
def usage(self, msg):
"""Print a brief error message to stderr and exit(2)."""
sys.stderr.write("Error: %s\n" % str(msg))
sys.stderr.write("For help, use %s -h\n" % self.progname)
sys.exit(2)
def parse_address(arg):
if "/" in arg:
family = socket.AF_UNIX
address = arg
else:
family = socket.AF_INET
if ":" in arg:
host, port = arg.split(":", 1)
else:
host = ""
port = arg
try:
port = int(port)
except: # int() can raise all sorts of errors
raise ValueError("invalid port number: %r" % port)
address = host, port
return family, address
class ZEOOptions(Options):
read_only = None
transaction_timeout = None
invalidation_queue_size = None
monitor_address = None
record = None
family = None # set by -a; AF_UNIX or AF_INET
address = None # set by -a; string or (host, port)
storages = None # set by -f
_short_options = "a:C:f:hm:r:"
_long_options = [
"address=",
"configuration=",
"filename=",
"help",
"monitor=",
"record=",
]
def handle_option(self, opt, arg):
# Alphabetical order please!
if opt in ("-a", "--address"):
try:
f, a = parse_address(arg)
except ValueError, err:
self.usage(str(err))
else:
self.family = f
self.address = a
elif opt in ("-m", "--monitor"):
try:
f, a = parse_address(arg)
except ValueError, err:
self.usage(str(err))
else:
self.monitor_family = f
self.monitor_address = a
elif opt in ("-f", "--filename"):
from ZODB.config import FileStorage
class FSConfig: class FSConfig:
def __init__(self, name, path): def __init__(self, name, path):
self._name = name self._name = name
...@@ -224,82 +70,52 @@ class ZEOOptions(Options): ...@@ -224,82 +70,52 @@ class ZEOOptions(Options):
def getSectionName(self): def getSectionName(self):
return self._name return self._name
if not self.storages: if not self.storages:
self.storages = {} self.storages = []
key = str(1 + len(self.storages)) name = str(1 + len(self.storages))
conf = FSConfig(key, arg) conf = FileStorage(FSConfig(name, arg))
self.storages[key] = FileStorage(conf) self.storages.append(conf)
elif opt in ("-r", "--record"):
self.record = arg def __init__(self):
else: self.schemadir = os.path.dirname(__file__)
# Pass it to the base class, for --help/-h ZDOptions.__init__(self)
Options.handle_option(self, opt, arg) self.add(None, None, "a:", "address=", self.handle_address)
self.add(None, None, "f:", "filename=", self.handle_filename)
def check_options(self): self.add("storages", "storages",
Options.check_options(self) # Calls load_configuration() required="no storages specified; use -f or -C")
if not self.storages: self.add("family", "zeo.address.family")
self.usage("no storages specified; use -f or -C") self.add("address", "zeo.address.address",
if self.family is None: required="no server address specified; use -a or -C")
self.usage("no server address specified; use -a or -C") self.add("read_only", "zeo.read_only", default=0)
self.add("invalidation_queue_size", "zeo.invalidation_queue_size",
default=100)
self.add("transaction_timeout", "zeo.transaction_timeout")
self.add("monitor_address", None, "m:", "monitor=",
self.handle_monitor_address)
self.add("record", None, "r:", "record=")
def realize(self, *args):
ZDOptions.realize(self, *args)
if self.args: if self.args:
self.usage("positional arguments are not supported") self.usage("positional arguments are not supported")
# Set defaults for some options
if self.read_only is None:
self.read_only = 0
if self.invalidation_queue_size is None:
self.invalidation_queue_size = 100
def load_configuration(self):
Options.load_configuration(self) # Sets self.rootconf
if not self.rootconf:
return
# Now extract options from various configuration sections
self.load_zeoconf()
self.load_logconf() self.load_logconf()
self.load_storages()
def load_zeoconf(self):
# Get some option values from the configuration
if self.family is None:
self.family = self.rootconf.zeo.address.family
self.address = self.rootconf.zeo.address.address
self.read_only = self.rootconf.zeo.read_only
self.transaction_timeout = self.rootconf.zeo.transaction_timeout
self.invalidation_queue_size = self.rootconf.zeo.invalidation_queue_size
def load_logconf(self): def load_logconf(self):
if self.rootconf.logger is not None: if self.configroot.logger is not None:
zLOG.set_initializer(self.log_initializer) zLOG.set_initializer(self.log_initializer)
zLOG.initialize() zLOG.initialize()
def log_initializer(self): def log_initializer(self):
from zLOG import EventLogger from zLOG import EventLogger
logger = self.rootconf.logger() logger = self.configroot.logger()
for handler in logger.handlers: for handler in logger.handlers:
if hasattr(handler, "reopen"): if hasattr(handler, "reopen"):
handler.reopen() handler.reopen()
EventLogger.event_logger.logger = logger EventLogger.event_logger.logger = logger
def load_storages(self):
# Get the storage specifications
if self.storages:
# -f option overrides
return
self.storages = {}
for opener in self.rootconf.storages:
self.storages[opener.name] = opener
class ZEOServer: class ZEOServer:
OptionsClass = ZEOOptions def __init__(self, options):
def __init__(self, options=None):
if options is None:
options = self.OptionsClass()
self.options = options self.options = options
def main(self): def main(self):
...@@ -338,10 +154,10 @@ class ZEOServer: ...@@ -338,10 +154,10 @@ class ZEOServer:
def open_storages(self): def open_storages(self):
self.storages = {} self.storages = {}
for name, opener in self.options.storages.items(): for opener in self.options.storages:
info("opening storage %r using %s" info("opening storage %r using %s"
% (name, opener.__class__.__name__)) % (opener.name, opener.__class__.__name__))
self.storages[name] = opener.open() self.storages[opener.name] = opener.open()
def setup_signals(self): def setup_signals(self):
"""Set up signal handlers. """Set up signal handlers.
...@@ -464,9 +280,11 @@ def _log(msg, severity=zLOG.INFO, error=None): ...@@ -464,9 +280,11 @@ def _log(msg, severity=zLOG.INFO, error=None):
# Main program # Main program
def main(args=None): def main(args=None):
options = ZEOOptions(args) options = ZEOOptions()
options.realize(args)
s = ZEOServer(options) s = ZEOServer(options)
s.main() s.main()
if __name__ == "__main__": if __name__ == "__main__":
__file__ = sys.argv[0]
main() main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment