diff --git a/gunicorn/config.py b/gunicorn/config.py new file mode 100644 index 00000000..e9ef2bf0 --- /dev/null +++ b/gunicorn/config.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 - +# +# This file is part of gunicorn released under the MIT license. +# See the NOTICE for more information. + +import os +import sys + +from gunicorn import util + +class Config(object): + + DEFAULTS = dict( + bind='127.0.0.1:8000', + daemon=False, + debug=False, + logfile='-', + loglevel='info', + pidfile=None, + workers=1, + umask=0, + user=None, + group=None, + + after_fork= lambda server, worker: server.logger.info( + "worker=%s spawned pid=%s}" % (worker.id, worker.pid)), + + before_fork= lambda server, worker: server.logger.info( + "worker=%s spawning" % worker.id) + ) + + def __init__(self, cmdopts, path=None): + if not path: + self.config_file = os.path.join(os.getcwd(), 'gunicorn.conf.py') + else: + self.config_file = os.path.abspath(os.path.normpath(path)) + self.cmdopts = cmdopts + self.conf = {} + self.load() + + def _load_file(self): + """ + Returns a dict of stuff found in the config file. + Defaults to $PWD/guniconf.py. + """ + if not os.path.exists(self.config_file): + return {} + + config = {} + try: + execfile(self.config_file, config) + except: + sys.exit("Could not read config file %r" % (self.config_file,)) + + config.pop("__builtins__", None) + return config + + def load(self): + self.conf = self.DEFAULTS.copy() + self.conf.update(self._load_file()) + for key, value in list(self.cmdopts.items()): + + if value and value is not None: + print "%s = %s" % (key, value) + self.conf[key] = value + + def __getitem__(self, key): + try: + return getattr(self, key) + except AttributeError: + pass + return self.conf[key] + + def __getattr__(self, key): + try: + getattr(super(Config, self), key) + except AttributeError: + if key in self.conf: + return self.conf[key] + raise + + def __contains__(self, key): + return (key in self.conf) + + def __iter__(self): + return self.conf.iteritems() + + @property + def workers(self): + if not self.conf.get('workers'): + raise RuntimeError("invalid workers number") + workers = int(self.conf["workers"]) + if not workers: + raise RuntimeError("number of workers < 1") + if self.conf['debug'] == True: + workers = 1 + return workers + + @property + def address(self): + if not self.conf['bind']: + raise RuntimeError("Listener address is not set") + return util.parse_address(self.conf['bind']) + + def after_fork(self, *args): + if not callable(self.conf['after_fork']): + raise RuntimeError("after_fork hook isn't a callable") + return self.conf['after_fork'](*args) + + def before_fork(self, *args): + if not callable(self.conf['before_fork']): + raise RuntimeError("before_fork hook isn't a callable") + return self.conf['after_fork'](*args) + + + + + + + + + + + \ No newline at end of file diff --git a/gunicorn/main.py b/gunicorn/main.py index f7eb09a1..51da1399 100644 --- a/gunicorn/main.py +++ b/gunicorn/main.py @@ -14,6 +14,7 @@ import re import sys from gunicorn.arbiter import Arbiter +from gunicorn.config import Config from gunicorn import util, __version__ LOG_LEVELS = { @@ -32,7 +33,7 @@ def options(): help='Config file. [%default]'), op.make_option('-b', '--bind', dest='bind', help='Adress to listen on. Ex. 127.0.0.1:8000 or unix:/tmp/gunicorn.sock'), - op.make_option('-w', '--workers', dest='workers', type='int', + op.make_option('-w', '--workers', dest='workers', help='Number of workers to spawn. [%default]'), op.make_option('-p','--pid', dest='pidfile', help='set the background PID FILE'), @@ -67,27 +68,6 @@ def configure_logging(opts): h.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s %(message)s")) logger.addHandler(h) -def get_config(path): - """ - Returns a dict of stuff found in the config file. - Defaults to $PWD/guniconf.py. - """ - filename = path or os.path.join(os.getcwd(), 'guniconf.py') - if not os.path.exists(filename): - if not path: - return None - else: - sys.exit('Could not find config file %r' % (filename,)) - - config = {} - try: - execfile(filename, config) - except: - sys.exit("Could not read config file %r" % (filename,)) - - config.pop("__builtins__", None) - return config - def daemonize(umask): if not 'GUNICORN_FD' in os.environ: if os.fork() == 0: @@ -127,67 +107,30 @@ def set_owner_process(user,group): os.setuid(uid) def main(usage, get_app): - default_options = dict( - bind='127.0.0.1:8000', - daemon=False, - debug=False, - logfile='-', - loglevel='info', - pidfile=None, - workers=1, - ) - parser = op.OptionParser(usage=usage, option_list=options(), version="%prog " + __version__) - parser.set_defaults(**default_options) opts, args = parser.parse_args() - - if opts.config: - conf_file = opts.config - else: - conf_file = os.path.join(os.getcwd(), "gunicorn.conf.py") - - if os.path.isfile(conf_file): - fileopts = get_config(conf_file) or {} - else: - fileopts = {} - - # optparse returns object, we want a dict - opts = opts.__dict__ - - # compare default with opts to see what is actually set - changes = dict(set(opts.items()).difference(set(default_options.items()))) - - # default_config < config file < config arguments - config = default_options.copy() - config.update(fileopts.items()) - config.update(changes.items()) - + conf = Config(opts.__dict__) app = get_app(parser, opts, args) - workers = config['workers'] - if config['debug']: - workers = 1 - - bind = config['bind'] or '127.0.0.1' - addr = util.parse_address(bind) + workers = conf['workers'] + addr = conf['address'] - umask = int(config['umask'] or UMASK) - kwargs = dict( - debug=config['debug'], - pidfile=config['pidfile'] + config=conf, + debug=conf['debug'], + pidfile=conf['pidfile'] ) arbiter = Arbiter(addr, workers, app, **kwargs) - if config['daemon']: - daemonize(umask) + if conf['daemon']: + daemonize(conf['umask']) else: os.setpgrp() - set_owner_process(config['user'], config['group']) - configure_logging(config) + set_owner_process(conf['user'], conf['group']) + configure_logging(conf) arbiter.run() def paste_server(app, global_conf=None, host="127.0.0.1", port=None, diff --git a/gunicorn/sock.py b/gunicorn/sock.py index 90c218ce..5592b9bf 100644 --- a/gunicorn/sock.py +++ b/gunicorn/sock.py @@ -65,7 +65,7 @@ class UnixSocket(BaseSocket): super(UnixSocket, self).__init__(addr, fd=fd) def __str__(self): - return "unix://%s" % self.address + return "unix:%s" % self.address def create_socket(addr): """\