diff options
Diffstat (limited to 'python/mozbuild/mozbuild/html_build_viewer.py')
-rw-r--r-- | python/mozbuild/mozbuild/html_build_viewer.py | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/python/mozbuild/mozbuild/html_build_viewer.py b/python/mozbuild/mozbuild/html_build_viewer.py new file mode 100644 index 0000000000..0582e6f1be --- /dev/null +++ b/python/mozbuild/mozbuild/html_build_viewer.py @@ -0,0 +1,118 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# This module contains code for running an HTTP server to view build info. +import http.server +import json +import os + +import requests + + +class HTTPHandler(http.server.BaseHTTPRequestHandler): + def do_GET(self): + s = self.server.wrapper + p = self.path + + if p == "/build_resources.json": + self.send_response(200) + self.send_header("Content-Type", "application/json; charset=utf-8") + self.end_headers() + + keys = sorted(s.json_files.keys()) + s = json.dumps({"files": ["resources/%s" % k for k in keys]}) + self.wfile.write(s.encode("utf-8")) + return + + if p.startswith("/resources/"): + key = p[len("/resources/") :] + + if key not in s.json_files: + self.send_error(404) + return + + self.send_response(200) + self.send_header("Content-Type", "application/json; charset=utf-8") + self.end_headers() + + self.wfile.write(s.json_files[key]) + return + + if p == "/": + p = "/build_resources.html" + + self.serve_docroot(s.doc_root, p[1:]) + + def do_POST(self): + if self.path == "/shutdown": + self.server.wrapper.do_shutdown = True + self.send_response(200) + return + + self.send_error(404) + + def serve_docroot(self, root, path): + local_path = os.path.normpath(os.path.join(root, path)) + + # Cheap security. This doesn't resolve symlinks, etc. But, it should be + # acceptable since this server only runs locally. + if not local_path.startswith(root): + self.send_error(404) + + if not os.path.exists(local_path): + self.send_error(404) + return + + if os.path.isdir(local_path): + self.send_error(500) + return + + self.send_response(200) + ct = "text/plain" + if path.endswith(".html"): + ct = "text/html" + + self.send_header("Content-Type", ct) + self.end_headers() + + with open(local_path, "rb") as fh: + self.wfile.write(fh.read()) + + +class BuildViewerServer(object): + def __init__(self, address="localhost", port=0): + # TODO use pkg_resources to obtain HTML resources. + pkg_dir = os.path.dirname(os.path.abspath(__file__)) + doc_root = os.path.join(pkg_dir, "resources", "html-build-viewer") + assert os.path.isdir(doc_root) + + self.doc_root = doc_root + self.json_files = {} + + self.server = http.server.HTTPServer((address, port), HTTPHandler) + self.server.wrapper = self + self.do_shutdown = False + + @property + def url(self): + hostname, port = self.server.server_address + return "http://%s:%d/" % (hostname, port) + + def add_resource_json_file(self, key, path): + """Register a resource JSON file with the server. + + The file will be made available under the name/key specified.""" + with open(path, "rb") as fh: + self.json_files[key] = fh.read() + + def add_resource_json_url(self, key, url): + """Register a resource JSON file at a URL.""" + r = requests.get(url) + if r.status_code != 200: + raise Exception("Non-200 HTTP response code") + self.json_files[key] = r.text + + def run(self): + while not self.do_shutdown: + self.server.handle_request() |