mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
Create an application abstraction.
Groundwork for providing a post-fork app import option. Fixes paster's ini not being able to register changes.
This commit is contained in:
parent
63e39e1232
commit
5268b8fbbb
94
gunicorn/app.py
Normal file
94
gunicorn/app.py
Normal file
@ -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)
|
||||
@ -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:
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user