diff --git a/salt/hg/config/hg.apache.conf.jinja b/salt/hg/config/hg.apache.conf.jinja index c11bbfb5..16cb7433 100644 --- a/salt/hg/config/hg.apache.conf.jinja +++ b/salt/hg/config/hg.apache.conf.jinja @@ -24,6 +24,14 @@ Require all granted + Alias /icons/ "/usr/share/apache2/icons/" + + + Options FollowSymlinks + AllowOverride None + Require all granted + + # The lookup app is better run with few processes, since it uses a cache. WSGIDaemonProcess hglookup user=hg group=hg \ threads=2 processes=1 maximum-requests=1000 \ @@ -36,38 +44,38 @@ WSGIScriptAlias /lookup /srv/hg/wsgi/lookup.wsgi - # We need enough threads/processes for many long-running clones to run in - # parallel (e.g. for buildbots) - # NOTE: maximum-requests suspected to corrupt responses, see - # http://mercurial.selenic.com/bts/issue2595 - WSGIDaemonProcess hgweb user=hg group=hg \ - threads=2 processes=6 maximum-requests=1024 inactivity-timeout=300 \ - display-name=hgweb - WSGIProcessGroup hgweb + # A lightweight standin for revision app to maintain support for /lookup + WSGIDaemonProcess hgrev user=hg group=hg \ + threads=2 processes=4 maximum-requests=1000 \ + display-name=hgrev + # The Location hack ensures the lookup app is run within + # this process group + + WSGIProcessGroup hgrev + + + WSGIScriptAliasMatch "^(.*)/rev/([A-Fa-f0-9]{12,40})/?" /srv/hg/wsgi/rev.wsgi - WSGIScriptAlias / /srv/hg/wsgi/python.wsgi + # Staticly serve hg repos over HTTP + DocumentRoot /srv/hg/hg-static/ + + Options Indexes FollowSymlinks + IndexOptions FancyIndexing SuppressColumnSorting + HeaderName README.html + Require all granted + ErrorDocument 410 /410.html RedirectMatch gone "/cpython/annotate/.*/NEWS$" RedirectMatch gone "/cpython-fullhistory/annotate/.*/NEWS$" - - Require all granted - - # Static files: logo, CSS, favicon... (wired to .../static/) # This is optional but a bit faster than letting Mercurial serve the files # NOTE: needs to be changed if hg gets wired to another dir or python # version - AliasMatch /static/([^/]*) /usr/share/mercurial/templates/static/$1 - - Require all granted - - SetHandler server-status - Require ip 127.0.0.1 diff --git a/salt/hg/files/hg/src/hgrev.py b/salt/hg/files/hg/src/hgrev.py new file mode 100644 index 00000000..36599e65 --- /dev/null +++ b/salt/hg/files/hg/src/hgrev.py @@ -0,0 +1,60 @@ +# hgrev.py +# +# Dump a revision of a given hg repo as a patch +# +# Written by Ee Durbin, 2025. + +import os +import shlex +import subprocess +from wsgiref.simple_server import make_server + + +class hgrev(object): + def __init__(self, verbose=False): + self.verbose = verbose + + def successful_response(self, response, contents): + headers = [("Content-Type", "text/plain")] + response("200 OK", headers) + return [contents.encode()] + + def failed_response(self, response, detail=""): + headers = [("Content-Type", "text/plain")] + response("404 Not Found", headers) + return [ + detail.encode(), + "\nUsage: path/to/hg/repo/rev/HGHEXNODE (12 or 40 hex characters)\n".encode(), + ] + + def __call__(self, env, response): + node = env.get("SCRIPT_NAME", "").strip("/") + repository = os.path.dirname(node).rstrip("/rev") + rev = os.path.basename(node) + + hg_repo = os.path.join("/srv/hg/repos", repository, ".hg") + if not os.path.exists(hg_repo): + return self.failed_response( + response, + detail=f"repo not found ({repository}) ({rev})", + ) + + command = ["hg", "log", "-v", "-p", "-r", shlex.quote(rev)] + + try: + result = subprocess.run( + command, cwd=hg_repo, capture_output=True, text=True, shell=False + ) + except Exception as e: + return self.failed_response(response, detail=str(e)) + + return self.successful_response(response, result.stdout) + + +if __name__ == "__main__": + application = hgrev(verbose=True) + + httpd = make_server("", 8124, application) + sa = httpd.socket.getsockname() + print("Serving HTTP on", sa[0], "port", sa[1], "...") + httpd.serve_forever() diff --git a/salt/hg/files/hg/wsgi/rev.wsgi b/salt/hg/files/hg/wsgi/rev.wsgi new file mode 100644 index 00000000..1217018f --- /dev/null +++ b/salt/hg/files/hg/wsgi/rev.wsgi @@ -0,0 +1,10 @@ +import os +import sys + +home = os.path.expanduser('~hg') + +sys.path.insert(0, os.path.join(home, 'src')) + +from hgrev import hgrev + +application = hgrev()