diff --git a/gunicorn/app.py b/gunicorn/app.py new file mode 100644 index 00000000..cc2c988c --- /dev/null +++ b/gunicorn/app.py @@ -0,0 +1,94 @@ +# -*- 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 Application(object): + """\ + An application interface for configuring and loading + the various necessities for any given web framework. + """ + + def get_config(self): + return {} + + def load(self): + raise NotImplementedError + +class WSGIApplication(Application): + + def __init__(self, app_uri): + self.app_uri = app_uri + + def load(self): + return util.import_app(self.app_uri) + +class DjangoApplication(Application): + + def __init__(self, settings_modname, project_path): + self.project_path = project_path + self.settings_modname = settings_modname + + # update sys.path + sys.path.insert(0, project_path) + sys.path.append(os.path.join(project_path, os.pardir)) + + def load(self): + import django.core.handlers.wsgi + os.environ['DJANGO_SETTINGS_MODULE'] = self.settings_modname + return django.core.handlers.wsgi.WSGIHandler() + +class PasterApplication(Application): + + def __init__(self, cfgurl, relpath, global_opts): + self.cfgurl = cfgurl + self.relpath = relpath + self.global_opts = global_opts + + def local_conf(self): + from paste.deploy import loadwsgi + ctx = loadwsgi.loadcontext(loadwsgi.SERVER, self.cfgurl, + relative_to=self.relpath) + + def mk_bind(): + host = ctx.local_conf.get('host') + port = ctx.local_conf.get('port') + if host and port: + return '%s:%s' % (host, port) + elif host: + return host + + ret = {} + vars = { + 'bind': mk_bind, + 'workers': lambda: ctx.local_conf.get('workers', 1), + 'umask': lambda: int(ctx.local_conf.get('umask', UMASK)), + 'group': lambda: ctx.local_conf.get('group'), + 'user': lambda: ctx.local_conf.get('user') + } + for vn in vars: + if self.global_ops.get(vn): + val = vars[vn]() + if val: + ret[vn] = val + + keys = ctx.local_conf.items() + keys = filter(self.global_opts.get, keys) + keys = filter(ret.has_key, keys) + ret.update((k, ctx.local_conf[k]) for k in keys) + + if not self.global_opts.get("debug"): + ret['debug'] = (ctx.global_conf.get('debug') == "true") + + ret['default_proc_name'] = ctx.global_conf.get('__file__') + + return ret + + def load(self): + from paste.deploy import loadapp + return loadapp(self.cfgurl, relative_to=self.relpath) diff --git a/gunicorn/config.py b/gunicorn/config.py index 04e47a4f..5ebbe848 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -44,19 +44,30 @@ class Config(object): ) def __init__(self, opts, path=None): - self.cfg = self.DEFAULTS.copy() - + self.cfg = {} + self.opts = opts if path is None: path = os.path.join(os.getcwd(), self.DEFAULT_CONFIG_FILE) - if os.path.exists(path): + self.path = path + self.load() + + def update(self, opts): + opts = dict((k, v) for (k, v) in opts.iteritems() if v is not None) + self.opts.update(opts) + self.cfg.update(opts) + + def load(self): + self.cfg = self.DEFAULTS.copy() + + if os.path.exists(self.path): try: - execfile(path, globals(), self.cfg) + execfile(self.path, globals(), self.cfg) except Exception, e: - sys.exit("Could not read config file: %r\n %s" % (path, e)) + sys.exit("Could not read config file: %r\n %s" % (self.path, e)) self.cfg.pop("__builtins__", None) - opts = [(k, v) for (k, v) in opts.iteritems() if v is not None] - self.cfg.update(dict(opts)) + opts = dict((k, v) for (k, v) in opts.iteritems() if v is not None) + self.cfg.update(opts) def __getitem__(self, key): try: diff --git a/gunicorn/main.py b/gunicorn/main.py index 7d012f85..2b2324f2 100644 --- a/gunicorn/main.py +++ b/gunicorn/main.py @@ -69,6 +69,7 @@ def main(usage, get_app): cfg = Config(opts.__dict__, opts.config) app = get_app(parser, opts, args) + cfg.update(app.get_config()) if cfg.spew: spew() if cfg.daemon: @@ -77,7 +78,7 @@ def main(usage, get_app): os.setpgrp() configure_logging(cfg) - Arbiter(cfg, app).run() + Arbiter(cfg, app.load()).run() def run(): """\ @@ -90,10 +91,13 @@ def run(): if len(args) != 1: parser.error("No application module specified.") opts.default_proc_name = args[0] + + application = app.WSGIApplication(args[0]) try: - return util.import_app(args[0]) + application.load() except Exception, e: parser.error("Failed to import application module:\n %s" % e) + return application main("%prog [OPTIONS] APP_MODULE", get_app) @@ -124,22 +128,15 @@ def run_django(): settings_path = os.path.join(project_path, "settings.py") if not os.path.exists(settings_path): settings_notfound(settings_path) - - project_name = os.path.split(project_path)[-1] - - sys.path.insert(0, project_path) - sys.path.append(os.path.join(project_path, os.pardir)) # set environ + project_name = os.path.split(project_path)[-1] settings_name, ext = os.path.splitext(os.path.basename(settings_path)) - - settings_modname = '%s.%s' % (project_name, settings_name) - os.environ['DJANGO_SETTINGS_MODULE'] = settings_modname - + settings_modname = "%s.%s" % (project_name, settings_name) opts.default_proc_name = settings_modname # django wsgi app - return django.core.handlers.wsgi.WSGIHandler() + return app.DjangoApplication(settings_modname, project_path) @@ -150,7 +147,7 @@ def run_paster(): The ``gunicorn_paster`` command for launcing Paster compatible apllications like Pylons or Turbogears2 """ - from paste.deploy import loadapp, loadwsgi + from paste.deploy import loadwsgi def get_app(parser, opts, args): if len(args) != 1: @@ -169,43 +166,8 @@ def run_paster(): # add to eggs pkg_resources.working_set.add_entry(relpath) - ctx = loadwsgi.loadcontext(loadwsgi.SERVER, cfgurl, relative_to=relpath) - - if not opts.workers: - opts.workers = ctx.local_conf.get('workers', 1) - - if not opts.umask: - opts.umask = int(ctx.local_conf.get('umask', UMASK)) - - if not opts.group: - opts.group = ctx.local_conf.get('group') - - if not opts.user: - opts.user = ctx.local_conf.get('user') - - if not opts.bind: - host = ctx.local_conf.get('host') - port = ctx.local_conf.get('port') - if host: - if port: - bind = "%s:%s" % (host, port) - else: - bind = host - opts.bind = bind - - for k, v in ctx.local_conf.items(): - if not hasattr(opts, k): - setattr(opts, k, v) - - if not opts.debug: - opts.debug = (ctx.global_conf.get('debug') == "true") - - - opts.default_proc_name= ctx.global_conf.get('__file__') - - app = loadapp(cfgurl, relative_to=relpath) - return app + return app.PasterApplication(cfgurl, relpath, opts.__dict__) main("%prog [OPTIONS] pasteconfig.ini", get_app)