# HG changeset patch # User mpm@selenic.com # Date 1117067230 28800 # Node ID be7103467d2e0051928e8c0e74988632d1e25734 # Parent 2653740d811892ea471bd70441b8c8f31e40105d Add 'hg serve' command for stand-alone server This adds a simple stand-alone web server mode to hg that exports the current repo for merging and browsing. The default port is 8000. diff -r 2653740d8118 -r be7103467d2e hg --- a/hg Wed May 25 16:21:06 2005 -0800 +++ b/hg Wed May 25 16:27:10 2005 -0800 @@ -37,6 +37,7 @@ log show revision history of a single file merge merge changes from into local repository remove [files...] remove the given files in the next commit + serve export the repository via HTTP status show new, missing, and changed files in working dir tags show current changeset tags """ @@ -548,6 +549,22 @@ if errors: ui.warn("%d integrity errors encountered!\n" % errors) sys.exit(1) + +elif cmd == "serve": + from mercurial import hgweb + + soptions = {} + opts = [('p', 'port', 8000, 'listen port'), + ('a', 'address', '', 'interface address'), + ('n', 'name', os.getcwd(), 'repository name'), + ('t', 'templates', "", 'template map') + ] + + args = fancyopts.fancyopts(args, opts, soptions, + 'hg serve [options]') + + hgweb.server(repo.root, soptions["name"], soptions["templates"], + soptions["address"], soptions["port"]) else: print "unknown command\n" diff -r 2653740d8118 -r be7103467d2e mercurial/hgweb.py --- a/mercurial/hgweb.py Wed May 25 16:21:06 2005 -0800 +++ b/mercurial/hgweb.py Wed May 25 16:27:10 2005 -0800 @@ -578,5 +578,64 @@ else: write(self.t("error")) -if __name__ == "__main__": - hgweb().run() +def server(path, name, templates, address, port): + + import BaseHTTPServer + import sys, os + + class hgwebhandler(BaseHTTPServer.BaseHTTPRequestHandler): + def do_POST(self): + self.do_hgweb() + + def do_GET(self): + self.do_hgweb() + + def do_hgweb(self): + query = "" + p = self.path.find("?") + if p: + query = self.path[p + 1:] + query = query.replace('+', ' ') + + env = {} + env['GATEWAY_INTERFACE'] = 'CGI/1.1' + env['REQUEST_METHOD'] = self.command + if query: + env['QUERY_STRING'] = query + host = self.address_string() + if host != self.client_address[0]: + env['REMOTE_HOST'] = host + env['REMOTE_ADDR'] = self.client_address[0] + + if self.headers.typeheader is None: + env['CONTENT_TYPE'] = self.headers.type + else: + env['CONTENT_TYPE'] = self.headers.typeheader + length = self.headers.getheader('content-length') + if length: + env['CONTENT_LENGTH'] = length + accept = [] + for line in self.headers.getallmatchingheaders('accept'): + if line[:1] in "\t\n\r ": + accept.append(line.strip()) + else: + accept = accept + line[7:].split(',') + env['HTTP_ACCEPT'] = ','.join(accept) + + os.environ.update(env) + + save = sys.argv, sys.stdin, sys.stdout, sys.stderr + try: + sys.stdin = self.rfile + sys.stdout = self.wfile + sys.argv = ["hgweb.py"] + if '=' not in query: + sys.argv.append(query) + self.send_response(200, "Script output follows") + hg.run() + finally: + sys.argv, sys.stdin, sys.stdout, sys.stderr = save + + hg = hgweb(path, name, templates) + httpd = BaseHTTPServer.HTTPServer((address, port), hgwebhandler) + httpd.serve_forever()