188448d9ae4dfff1805045790ef5f32495d62abccJeff Brown#!/usr/bin/env python
288448d9ae4dfff1805045790ef5f32495d62abccJeff Brown# Copyright (c) 2012 The Chromium Authors. All rights reserved.
388448d9ae4dfff1805045790ef5f32495d62abccJeff Brown# Use of this source code is governed by a BSD-style license that can be
488448d9ae4dfff1805045790ef5f32495d62abccJeff Brown# found in the LICENSE file.
566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisimport json
688448d9ae4dfff1805045790ef5f32495d62abccJeff Brownimport optparse
788448d9ae4dfff1805045790ef5f32495d62abccJeff Brownimport os
888448d9ae4dfff1805045790ef5f32495d62abccJeff Brownimport sys
94849cead45edf85cf2a61526c0b716eb637f74baJeff Brownimport time
1066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisimport traceback
1166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisfrom build import generate_deps_js_contents as deps_generator
1266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisfrom build import generate_template_contents as template_generator
1388448d9ae4dfff1805045790ef5f32495d62abccJeff Brown
1466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisimport SocketServer
1588448d9ae4dfff1805045790ef5f32495d62abccJeff Brownimport SimpleHTTPServer
1688448d9ae4dfff1805045790ef5f32495d62abccJeff Brownimport BaseHTTPServer
1788448d9ae4dfff1805045790ef5f32495d62abccJeff Brown
1888448d9ae4dfff1805045790ef5f32495d62abccJeff BrownDEFAULT_PORT = 8003
1966a37686207944273ced825e0e8b6b6375f8c3deJamie GennisDEPS_CHECK_DELAY = 30
2066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
2166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennistoplevel_dir = os.path.abspath(os.path.dirname(__file__))
2266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennissrc_dir = os.path.join(toplevel_dir, 'src')
2366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennistest_data_dir = os.path.join(toplevel_dir, 'test_data')
2488448d9ae4dfff1805045790ef5f32495d62abccJeff Brown
2588448d9ae4dfff1805045790ef5f32495d62abccJeff Brownclass Handler(SimpleHTTPServer.SimpleHTTPRequestHandler):
2666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  def __init__(self, *args, **kwargs):
2766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, *args, **kwargs)
2866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
2966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  def send_response(self, code, message=None):
3066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    SimpleHTTPServer.SimpleHTTPRequestHandler.send_response(self, code, message)
3166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if code == 200:
3266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      self.send_header('Cache-Control', 'no-cache')
3366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
3466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  def do_GET_json_tests(self):
3566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    def is_test(x):
3666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      basename = os.path.basename(x)
3766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      if basename.startswith('.'):
3866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        return False
3966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
4066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      if basename.endswith('_test.js'):
4166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        return True
4266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return False
4366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
4466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    test_filenames = []
4566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    for dirpath, dirnames, filenames in os.walk(src_dir):
4666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      for f in filenames:
4766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        x = os.path.join(dirpath, f)
4866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        y = '/' + os.path.relpath(x, toplevel_dir)
4966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        if is_test(y):
5066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          test_filenames.append(y)
5166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
5266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    test_filenames.sort()
5366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
5466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    tests_as_json = json.dumps(test_filenames)
5566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
5666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.send_response(200)
5766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.send_header('Content-Type', 'application/json')
5866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.send_header('Content-Length', len(tests_as_json))
5966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.end_headers()
6066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.wfile.write(tests_as_json)
6166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
6266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  def do_GET_example_files(self):
6366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    data_files = []
6466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    for dirpath, dirnames, filenames in os.walk(test_data_dir):
6566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      for f in filenames:
6666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        data_files.append(f)
6766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
6866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    data_files.sort()
6966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    files_as_json = json.dumps(data_files)
7066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
7166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.send_response(200)
7266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.send_header('Content-Type', 'application/json')
7366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.send_header('Content-Length', len(files_as_json))
7466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.end_headers()
7566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.wfile.write(files_as_json)
7666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
7766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  def do_GET_deps(self):
7866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    current_time = time.time()
7966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if self.server.next_deps_check < current_time:
8066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      self.log_message('Regenerating ' + self.path)
8166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      try:
8266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        self.server.deps = deps_generator.generate_deps_js()
8366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      except Exception, ex:
8466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        msg = json.dumps({"details": traceback.format_exc(),
8566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis                          "message": ex.message});
8666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        self.log_error('While parsing deps: %s', ex.message)
8766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        self.send_response(500)
8866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        self.send_header('Content-Type', 'application/json')
8966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        self.send_header('Cache-Control', 'no-cache')
9066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        self.send_header('Content-Length', len(msg))
9166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        self.end_headers()
9266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        self.wfile.write(msg)
9366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        return
9466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
9566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      self.server.next_deps_check = current_time + DEPS_CHECK_DELAY
9666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
9766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.send_response(200)
9866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.send_header('Content-Type', 'application/javascript')
9966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.send_header('Content-Length', len(self.server.deps))
10066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.end_headers()
10166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.wfile.write(self.server.deps)
10266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
10366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  def do_GET_templates(self):
10466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    templates = template_generator.generate_templates()
10566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
10666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.send_response(200)
10766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.send_header('Content-Type', 'text/html')
10866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.send_header('Content-Length', len(templates))
10966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.end_headers()
11066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.wfile.write(templates)
11166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
11288448d9ae4dfff1805045790ef5f32495d62abccJeff Brown  def do_GET(self):
11366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if self.path == '/json/examples':
11466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      self.do_GET_example_files()
11566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return
11666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
11766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if self.path == '/json/tests':
11866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      self.do_GET_json_tests()
11966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return
12066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
12166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if self.path == '/templates':
12266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      self.do_GET_templates()
12366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return
12466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
12566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if self.path == '/deps.js':
12666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      self.do_GET_deps()
12766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return
12866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
12988448d9ae4dfff1805045790ef5f32495d62abccJeff Brown    return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
13088448d9ae4dfff1805045790ef5f32495d62abccJeff Brown
13166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  def log_error(self, format, *args):
13266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if self.path == '/favicon.ico':
13366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return
13466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.log_message("While processing %s: ", self.path)
13566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    SimpleHTTPServer.SimpleHTTPRequestHandler.log_error(self, format, *args)
13666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
13766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  def log_request(self, code='-', size='-'):
13866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    # Dont spam the console unless it is important.
13966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    pass
14066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
14166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
14266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisclass Server(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
1434849cead45edf85cf2a61526c0b716eb637f74baJeff Brown  def __init__(self, *args, **kwargs):
1444849cead45edf85cf2a61526c0b716eb637f74baJeff Brown    BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs)
1454849cead45edf85cf2a61526c0b716eb637f74baJeff Brown    self.next_deps_check = -1
14666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    self.deps = None
14788448d9ae4dfff1805045790ef5f32495d62abccJeff Brown
14888448d9ae4dfff1805045790ef5f32495d62abccJeff Browndef Main(args):
14988448d9ae4dfff1805045790ef5f32495d62abccJeff Brown  parser = optparse.OptionParser()
15088448d9ae4dfff1805045790ef5f32495d62abccJeff Brown  parser.add_option('--port',
15188448d9ae4dfff1805045790ef5f32495d62abccJeff Brown                    action='store',
15288448d9ae4dfff1805045790ef5f32495d62abccJeff Brown                    type='int',
15388448d9ae4dfff1805045790ef5f32495d62abccJeff Brown                    default=DEFAULT_PORT,
15488448d9ae4dfff1805045790ef5f32495d62abccJeff Brown                    help='Port to serve from')
15588448d9ae4dfff1805045790ef5f32495d62abccJeff Brown  options, args = parser.parse_args()
15688448d9ae4dfff1805045790ef5f32495d62abccJeff Brown  server = Server(('', options.port), Handler)
15788448d9ae4dfff1805045790ef5f32495d62abccJeff Brown  sys.stderr.write("Now running on http://localhost:%i\n" % options.port)
15888448d9ae4dfff1805045790ef5f32495d62abccJeff Brown  server.serve_forever()
15988448d9ae4dfff1805045790ef5f32495d62abccJeff Brown
16088448d9ae4dfff1805045790ef5f32495d62abccJeff Brownif __name__ == '__main__':
16166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  os.chdir(toplevel_dir)
16288448d9ae4dfff1805045790ef5f32495d62abccJeff Brown  sys.exit(Main(sys.argv[1:]))
163