2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
13 from tvcm import parse_deps
14 from tvcm import project as project_module
15 from tvcm import generate
16 from tvcm import resource_loader
19 import SimpleHTTPServer
24 class DevServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
25 def __init__(self, *args, **kwargs):
26 SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, *args, **kwargs)
28 def send_response(self, code, message=None):
29 SimpleHTTPServer.SimpleHTTPRequestHandler.send_response(self, code, message)
31 self.send_header('Cache-Control', 'no-cache')
34 if self.do_path_handler('GET'):
37 return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
40 if self.do_path_handler('POST'):
42 return SimpleHTTPServer.SimpleHTTPRequestHandler.do_POST(self)
45 def do_path_handler(self, method):
46 handler = self.server.GetPathHandler(self.path, method)
51 msg = json.dumps({"details": traceback.format_exc(),
52 "message": ex.message});
53 self.log_error('While parsing %s: %s', self.path, ex.message)
54 self.send_response(500)
55 self.send_header('Content-Type', 'application/json')
56 self.send_header('Cache-Control', 'no-cache')
57 self.send_header('Content-Length', len(msg))
63 def translate_path(self, path):
64 path = path.split('?',1)[0]
65 path = path.split('#',1)[0]
66 for mapped_path in self.server.project.source_paths:
67 rel = os.path.relpath(path, '/')
68 candidate = os.path.join(mapped_path, rel)
69 if os.path.exists(candidate):
73 def log_error(self, format, *args):
74 if self.server._quiet:
76 if self.path == '/favicon.ico':
78 self.log_message("While processing %s: ", self.path)
79 SimpleHTTPServer.SimpleHTTPRequestHandler.log_error(self, format, *args)
81 def log_request(self, code='-', size='-'):
82 # Dont spam the console unless it is important.
85 def do_GET_json_tests(self):
86 test_module_names = self.server.project.FindAllTestModuleNames()
88 tests = {'test_module_names': test_module_names,
89 'test_links': self.server.test_links}
90 tests_as_json = json.dumps(tests);
92 self.send_response(200)
93 self.send_header('Content-Type', 'application/json')
94 self.send_header('Content-Length', len(tests_as_json))
96 self.wfile.write(tests_as_json)
99 def do_GET_deps(self):
101 self.server.update_deps_and_templates()
102 except Exception, ex:
103 msg = json.dumps({"details": traceback.format_exc(),
104 "message": ex.message});
105 self.log_error('While parsing deps: %s', ex.message)
106 self.send_response(500)
107 self.send_header('Content-Type', 'application/json')
108 self.send_header('Cache-Control', 'no-cache')
109 self.send_header('Content-Length', len(msg))
111 self.wfile.write(msg)
113 self.send_response(200)
114 self.send_header('Content-Type', 'application/javascript')
115 self.send_header('Content-Length', len(self.server.deps))
117 self.wfile.write(self.server.deps)
119 def do_GET_templates(self):
120 self.server.update_deps_and_templates()
121 self.send_response(200)
122 self.send_header('Content-Type', 'text/html')
123 self.send_header('Content-Length', len(self.server.templates))
125 self.wfile.write(self.server.templates)
128 class PathHandler(object):
129 def __init__(self, path, handler, supports_get, supports_post):
131 self.handler = handler
132 self.supports_get = supports_get
133 self.supports_post = supports_post
135 def CanHandle(self, path, method):
136 if path != self.path:
138 if method == 'GET' and self.supports_get:
140 if method == 'POST' and self.supports_post:
144 def do_GET_root(request):
145 request.send_response(301)
146 request.send_header("Location", request.server.default_path)
147 request.end_headers()
149 class DevServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
150 def __init__(self, port, quiet=False, project=None):
151 BaseHTTPServer.HTTPServer.__init__(self, ('', port), DevServerHandler)
154 port = self.server_address[1]
156 self._path_handlers = []
157 self._test_links = []
159 self._project = project
161 self._project = project_module.Project([])
163 self._next_deps_check = -1
166 self.AddPathHandler('/', do_GET_root)
167 self.AddPathHandler('', do_GET_root)
168 self.default_path = '/tvcm/tests.html'
170 # Redirect old tests.html places to the new location until folks have gotten used to its new
172 self.AddPathHandler('/src/tests.html', do_GET_root)
173 self.AddPathHandler('/tests.html', do_GET_root)
175 self.AddPathHandler('/tvcm/json/tests', do_GET_json_tests)
176 self.AddPathHandler('/tvcm/all_templates.html', do_GET_templates)
177 self.AddPathHandler('/tvcm/deps.js', do_GET_deps)
179 def AddPathHandler(self, path, handler, supports_get=True, supports_post=False):
180 self._path_handlers.append(PathHandler(path, handler, supports_get, supports_post))
182 def GetPathHandler(self, path, method):
183 for h in self._path_handlers:
184 if h.CanHandle(path, method):
188 def AddSourcePathMapping(self, file_system_path):
189 self._project.AddSourcePath(file_system_path)
191 def AddTestLink(self, path, title):
192 self._test_links.append({'path': path,
196 def test_links(self):
197 return self._test_links
203 def update_deps_and_templates(self):
204 current_time = time.time()
205 if self._next_deps_check >= current_time:
209 sys.stderr.write('Regenerating deps and templates\n')
211 load_sequence = self.project.calc_load_sequence()
212 self.deps = generate.generate_deps_js(
213 load_sequence, self.project)
214 self.templates = generate.generate_html_for_combined_templates(
216 self._next_deps_check = current_time + DEPS_CHECK_DELAY
222 def serve_forever(self):
224 sys.stderr.write("Now running on http://localhost:%i\n" % self._port)
225 BaseHTTPServer.HTTPServer.serve_forever(self)