quartz/scripts/serve.py

72 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""Local HTTP server with clean URL support (Netlify-style)."""
import argparse
import os
from http.server import HTTPServer, SimpleHTTPRequestHandler
from pathlib import Path
class CleanURLHandler(SimpleHTTPRequestHandler):
"""HTTP handler that resolves clean URLs like Netlify."""
def do_GET(self):
path = self.path.split("?")[0].split("#")[0]
fs_path = Path(self.directory) / path.lstrip("/")
if fs_path.is_file():
return super().do_GET()
if path.endswith("/"):
index = fs_path / "index.html"
if index.is_file():
self.path = path + "index.html"
return super().do_GET()
# Fallback: try path.html (e.g., /notes/ → notes.html)
stripped = path.rstrip("/")
if stripped:
html_file = Path(self.directory) / (stripped.lstrip("/") + ".html")
if html_file.is_file():
self.path = stripped + ".html"
return super().do_GET()
self.send_error(404)
return
if "." not in Path(path).name:
html_file = fs_path.with_suffix(".html")
if html_file.is_file():
self.path = path + ".html"
return super().do_GET()
index = fs_path / "index.html"
if index.is_file():
self.send_response(301)
self.send_header("Location", path + "/")
self.end_headers()
return
self.send_error(404)
def main():
parser = argparse.ArgumentParser(description="Local server with clean URL support")
parser.add_argument("--port", type=int, default=8080, help="Port (default: 8080)")
parser.add_argument("--dir", type=str, default=".", help="Directory to serve")
args = parser.parse_args()
directory = os.path.abspath(args.dir)
handler = lambda *a, **kw: CleanURLHandler(*a, directory=directory, **kw)
server = HTTPServer(("", args.port), handler)
print(f"Serving {directory} at http://localhost:{args.port}")
print("Press Ctrl+C to stop.")
try:
server.serve_forever()
except KeyboardInterrupt:
print("\nStopped.")
if __name__ == "__main__":
main()