Onset: version control where nobody waits and nothing gets lost. The on command, its core and onset-server.
| 6 |
| Usage: git-server.py <root> <port> |
| 7 | """ |
| 8 | import http.server |
| 9 | import os |
| 10 | import subprocess |
| 11 | import sys |
| 12 |
| 13 | ROOT, PORT = sys.argv[1], int(sys.argv[2]) |
| 14 |
| 15 |
| 16 | class Handler(http.server.BaseHTTPRequestHandler): |
| 17 | protocol_version = "HTTP/1.1" |
| 18 |
| 19 | def log_message(self, *args): |
| 20 | pass |
| 21 |
| 22 | def body(self): |
| 23 | if self.headers.get("transfer-encoding", "").lower() == "chunked": |
| 24 | out = bytearray() |
| 25 | while True: |
| 26 | size = int(self.rfile.readline().split(b";")[0].strip(), 16) |
| 27 | if size == 0: |
| 28 | while self.rfile.readline() not in (b"\r\n", b"\n", b""): |
| 29 | pass |
| 30 | return bytes(out) |
| 31 | out += self.rfile.read(size) |
| 32 | self.rfile.readline() |
| 33 | length = int(self.headers.get("content-length") or 0) |
| 34 | return self.rfile.read(length) if length else b"" |
| 35 |
| 36 | def serve(self): |
| 37 | path, _, query = self.path.partition("?") |
| 38 | data = self.body() |
| 39 | env = dict( |
| 40 | os.environ, |
| 41 | GIT_PROJECT_ROOT=ROOT, |
| 42 | GIT_HTTP_EXPORT_ALL="1", |
| 43 | REMOTE_USER="vcs", |
| 44 | REQUEST_METHOD=self.command, |
| 45 | PATH_INFO=path, |
| 46 | QUERY_STRING=query, |
| 47 | CONTENT_TYPE=self.headers.get("content-type", ""), |
| 48 | CONTENT_LENGTH=str(len(data)), |
| 49 | ) |
| 50 | if self.headers.get("content-encoding"): |
| 51 | env["HTTP_CONTENT_ENCODING"] = self.headers["content-encoding"] |
| 52 | out = subprocess.run(["git", "http-backend"], input=data, env=env, capture_output=True).stdout |
| 53 | sep = b"\r\n\r\n" if b"\r\n\r\n" in out else b"\n\n" |
| 54 | head, _, body = out.partition(sep) |
| 55 | status = 200 |
| 56 | headers = [] |
| 57 | for line in head.decode().splitlines(): |
| 58 | key, _, value = line.partition(":") |
| 59 | if key.lower() == "status": |
| 60 | status = int(value.strip().split()[0]) |
| 61 | elif key: |
| 62 | headers.append((key, value.strip())) |
| 63 | self.send_response(status) |
| 64 | for key, value in headers: |
| 65 | self.send_header(key, value) |
| 66 | self.send_header("content-length", str(len(body))) |
| 67 | self.end_headers() |
| 68 | self.wfile.write(body) |
| 69 |
| 70 | do_GET = serve |
| 71 | do_POST = serve |
| 72 |
| 73 |
| 74 | http.server.ThreadingHTTPServer(("127.0.0.1", PORT), Handler).serve_forever() |
| 75 |