-
Notifications
You must be signed in to change notification settings - Fork 0
/
dev_server.py
executable file
·200 lines (165 loc) · 6.56 KB
/
dev_server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#!/usr/bin/env python
"""Simple development server
Make sure you're use python 2.7 for developing
"""
import sys
import os
import os.path
import re
import imp
import yaml
from optparse import OptionParser
from sae.util import search_file_bottom_up
app_root = search_file_bottom_up('config.yaml')
if app_root is None:
print >> sys.stderr, \
'Error: Not an app directory(or any of the parent directories)'
sys.exit(1)
if app_root != os.getcwd(): os.chdir(app_root)
def setup_sae_environ(conf):
# Add dummy pylibmc module
import sae.memcache
sys.modules['pylibmc'] = sae.memcache
# Save kvdb data in this file else the data will lost
# when the dev_server.py is down
if conf.kvdb:
print 'KVDB: ', conf.kvdb
os.environ['sae.kvdb.file'] = conf.kvdb
# Add app_root to sys.path
cwd = os.getcwd()
if cwd not in sys.path:
sys.path.insert(0, cwd)
try:
appname = str(conf.name)
appversion = str(conf.version)
except AttributeError:
raise AttributeError('`name` or `version` not found in `config.yaml`')
if conf.mysql:
import sae.const
p = re.compile('^(.+):(.+)@(.+):(\d+)$')
m = p.match(conf.mysql)
if not m:
raise Exception("Invalid mysql configuration")
user, password, host, port = m.groups()
dbname = 'app_' + appname
sae.const.MYSQL_DB = dbname
sae.const.MYSQL_USER = user
sae.const.MYSQL_PASS = password
sae.const.MYSQL_PORT = port
sae.const.MYSQL_HOST = host
print 'MySQL: %s.%s' % (conf.mysql, dbname)
else:
print 'MySQL config not found'
if conf.storage:
os.environ['sae.storage.path'] = os.path.abspath(conf.storage)
# Add custom environment variable
os.environ['HTTP_HOST'] = '%s:%d' % (conf.host, conf.port)
os.environ['APP_NAME'] = appname
os.environ['APP_VERSION'] = appversion
class Worker:
def __init__(self, conf, app):
self.conf = conf
self.application = app
self.collect_statifiles()
def collect_statifiles(self):
self.static_files = {}
if hasattr(self.conf, 'handlers'):
for h in self.conf.handlers:
url = h['url']
if h.has_key('static_dir'):
self.static_files[url] = os.path.join(app_root, h['static_dir'])
elif h.has_key('static_path'):
self.static_files[url] = os.path.join(app_root, h['static_path'])
if not len(self.static_files):
self.static_files.update({
'/static': os.path.join(app_root, 'static'),
'/media': os.path.join(app_root, 'media'),
'/favicon.ico': os.path.join(app_root, 'favicon.ico'),
})
if self.conf.storage:
# stor dispatch: for test usage only
self.static_files['/stor-stub/'] = os.path.abspath(self.conf.storage)
def run(self):
raise NotImplementedError()
class WsgiWorker(Worker):
def run(self):
# FIXME: All files under current directory
files = ['index.wsgi']
# XXX:
# when django template renders `environ` in its 500 page, it will
# try to call `environ['werkzeug.server.shutdown'` and cause the
# server exit unexpectedly.
# See: https://docs.djangoproject.com/en/dev/ref/templates/api/#variables-and-lookups
def wrap(app):
def _(environ, start_response):
try:
del environ['werkzeug.server.shutdown']
except KeyError:
pass
return app(environ, start_response)
return _
if 'WERKZEUG_RUN_MAIN' in os.environ:
os.environ['sae.run_main'] = '1'
from werkzeug.serving import run_simple
run_simple(self.conf.host, self.conf.port,
wrap(self.application),
use_reloader = True,
use_debugger = True,
extra_files = files,
static_files = self.static_files)
class TornadoWorker(Worker):
def run(self):
import tornado.autoreload
tornado.autoreload.watch('index.wsgi')
import re
from tornado.web import URLSpec, StaticFileHandler
# The user should not use `tornado.web.Application.add_handlers`
# since here in SAE one application only has a single host, so here
# we can just use the first host_handers.
handlers = self.application.handlers[0][1]
for prefix, path in self.static_files.iteritems():
pattern = re.escape(prefix) + r"(.*)"
handlers.insert(0, URLSpec(pattern, StaticFileHandler, {"path": path}))
os.environ['sae.run_main'] = '1'
import tornado.ioloop
from tornado.httpserver import HTTPServer
server = HTTPServer(self.application, xheaders=True)
server.listen(self.conf.port, self.conf.host)
tornado.ioloop.IOLoop.instance().start()
def main(options):
conf_path = os.path.join(app_root, 'config.yaml')
conf = yaml.load(open(conf_path, "r"))
options.__dict__.update(conf)
conf = options
# if env `WERKZEUG_RUN_MAIN` is not defined, then we are in
# the reloader process.
# if os.environ.get('WERKZEUG_RUN_MAIN', False):
setup_sae_environ(conf)
try:
index = imp.load_source('index', 'index.wsgi')
except IOError:
print >>sys.stderr, "Seems you don't have an index.wsgi"
return
if not hasattr(index, 'application'):
print >>sys.stderr, "application not found in index.wsgi"
return
if not callable(index.application):
print >>sys.stderr, "application is not a callable"
return
application = index.application
cls_name = getattr(conf, 'worker', 'wsgi').capitalize() + 'Worker'
try:
globals().get(cls_name, WsgiWorker)(conf, application).run()
except KeyboardInterrupt:
pass
if __name__ == '__main__':
parser = OptionParser()
parser.add_option("-p", "--port", type="int", dest="port", default="8080",
help="Which port to listen")
parser.add_option("--host", dest="host", default="localhost",
help="Which host to listen")
parser.add_option("--mysql", dest="mysql", help="Mysql configuration: user:password@host:port")
parser.add_option("--storage-path", dest="storage", help="Directory used as local stoarge")
parser.add_option("--kvdb-file", dest="kvdb", help="File to save kvdb data")
(options, args) = parser.parse_args()
main(options)