{"thread":{"id":"50309","subject":"[PATCH v1] git-instaweb: Add Python builtin http.server support","startedAt":"2019-01-24T16:13:50Z","lastAt":"2019-01-28T18:27:14Z","messageCount":11,"participants":["Arti Zirk","Junio C Hamano","brian m. carlson"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"367561","messageId":"20190124161331.25945-1-arti.zirk@gmail.com","threadId":"50309","inReplyTo":null,"subject":"[PATCH v1] git-instaweb: Add Python builtin http.server support","fromName":"Arti Zirk","fromEmail":"arti.zirk@gmail.com","sentAt":"2019-01-24T16:13:31Z","receivedAt":"2019-01-24T16:13:50Z","isPatch":true,"sender":{"key":"arti.zirk@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1923870?v=4"},"body":"With this patch it is possible to launch git-instaweb by using\nPython 3 http.server CGI handler via `-d python` option.\n\ngit-instaweb generates a small wrapper around the http.server\n(in GIT_DIR/gitweb/) that address a limitation of the CGI handler\nwhere CGI scripts have to be in a cgi-bin subdirectory and\ndirectory index can't be easily changed. To keep the implementation\nsmall, gitweb is running on url `/cgi-bin/gitweb.cgi` and an automatic\nredirection is done when opening `/`.\n\nPython 3 is by default installed on most modern Linux distributions\nwhich enables running `git instaweb -d python` without needing\nanything else.\n\nSigned-off-by: Arti Zirk <arti.zirk@gmail.com>\n---\n\nNotes:\n    Base Ref: master\n    Web-Diff: https://github.com/artizirk/git/commit/a40d28ca58\n    Checkout: git fetch https://github.com/artizirk/git instaweb-python-v1 && git checkout a40d28ca58\n\n Documentation/git-instaweb.txt |   3 +-\n git-instaweb.sh                | 114 ++++++++++++++++++++++++++++++++-\n 2 files changed, 115 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-instaweb.txt b/Documentation/git-instaweb.txt\nindex e8ecdbf927..a54fe4401b 100644\n--- a/Documentation/git-instaweb.txt\n+++ b/Documentation/git-instaweb.txt\n@@ -29,7 +29,8 @@ OPTIONS\n \tThe HTTP daemon command-line that will be executed.\n \tCommand-line options may be specified here, and the\n \tconfiguration file will be added at the end of the command-line.\n-\tCurrently apache2, lighttpd, mongoose, plackup and webrick are supported.\n+\tCurrently apache2, lighttpd, mongoose, plackup, python and\n+\twebrick are supported.\n \t(Default: lighttpd)\n \n -m::\ndiff --git a/git-instaweb.sh b/git-instaweb.sh\nindex eec264e630..c8f9f03447 100755\n--- a/git-instaweb.sh\n+++ b/git-instaweb.sh\n@@ -67,6 +67,13 @@ resolve_full_httpd () {\n \t\thttpd_only=\"${httpd%% *}\" # cut on first space\n \t\treturn\n \t\t;;\n+\t*python*)\n+\t\t# server is started by running via generated gitweb.py in\n+\t\t# $fqgitdir/gitweb\n+\t\tfull_httpd=\"$fqgitdir/gitweb/gitweb.py\"\n+\t\thttpd_only=\"${httpd%% *}\" # cut on first space\n+\t\treturn\n+\t\t;;\n \tesac\n \n \thttpd_only=\"$(echo $httpd | cut -f1 -d' ')\"\n@@ -110,7 +117,7 @@ start_httpd () {\n \n \t# don't quote $full_httpd, there can be arguments to it (-f)\n \tcase \"$httpd\" in\n-\t*mongoose*|*plackup*)\n+\t*mongoose*|*plackup*|*python*)\n \t\t#These servers don't have a daemon mode so we'll have to fork it\n \t\t$full_httpd \"$conf\" &\n \t\t#Save the pid before doing anything else (we'll print it later)\n@@ -595,6 +602,108 @@ EOF\n \trm -f \"$conf\"\n }\n \n+python_conf() {\n+\t# Python's builtin http.server and its CGI support is very limited.\n+\t# CGI handler is capable of running CGI script only from inside a directory.\n+\t# Trying to set cgi_directories=[\"/\"] will add double slash to SCRIPT_NAME\n+\t# and that in turn breaks gitweb's relative link generation.\n+\n+\t# create a simple web root where $fqgitdir/gitweb/$httpd_only is our root\n+\tmkdir -p \"$fqgitdir/gitweb/$httpd_only/cgi-bin\"\n+\t# Python http.server follows the symlinks\n+\tln -sf \"$root/gitweb.cgi\" \"$fqgitdir/gitweb/$httpd_only/cgi-bin/gitweb.cgi\"\n+\tln -sf \"$root/static\" \"$fqgitdir/gitweb/$httpd_only/\"\n+\n+\t# generate a standalone 'python3 http.server' script in $fqgitdir/gitweb\n+\t# This asumes that python3 is in user's $PATH\n+\tcat > \"$fqgitdir/gitweb/gitweb.py\" <<EOF\n+#!/usr/bin/env python3\n+import os\n+import sys\n+\n+# Open log file in line buffering mode\n+accesslogfile = open(\"$fqgitdir/gitweb/access.log\", 'a', buffering=1)\n+errorlogfile = open(\"$fqgitdir/gitweb/error.log\", 'a', buffering=1)\n+\n+# and replace our stdout and stderr with log files\n+# also do a lowlevel duplicate of the logfile file descriptors so that\n+# our CGI child process writes any stderr warning also to the log file\n+_orig_stdout_fd = sys.stdout.fileno()\n+sys.stdout.close()\n+os.dup2(accesslogfile.fileno(), _orig_stdout_fd)\n+sys.stdout = accesslogfile\n+\n+_orig_stderr_fd = sys.stderr.fileno()\n+sys.stderr.close()\n+os.dup2(errorlogfile.fileno(), _orig_stderr_fd)\n+sys.stderr = errorlogfile\n+\n+from functools import partial\n+from http.server import CGIHTTPRequestHandler, test\n+\n+# Those environment variables will be passed to the cgi script\n+os.environ.update({\n+\t\"GIT_EXEC_PATH\": \"$GIT_EXEC_PATH\",\n+\t\"GIT_DIR\": \"$GIT_DIR\",\n+\t\"GITWEB_CONFIG\": \"$GITWEB_CONFIG\"\n+})\n+\n+\n+class GitWebRequestHandler(CGIHTTPRequestHandler):\n+\n+\tdef log_message(self, format, *args):\n+\t\t# Write access logs to stdout\n+\t\tsys.stdout.write(\"%s - - [%s] %s\\n\" %\n+\t\t\t\t(self.address_string(),\n+\t\t\t\tself.log_date_time_string(),\n+\t\t\t\tformat%args))\n+\n+\tdef do_HEAD(self):\n+\t\tself.redirect_path()\n+\t\tsuper().do_HEAD()\n+\n+\tdef do_GET(self):\n+\t\tif self.path == \"/\":\n+\t\t\tself.send_response(303, \"See Other\")\n+\t\t\tself.send_header(\"Location\", \"/cgi-bin/gitweb.cgi\")\n+\t\t\tself.end_headers()\n+\t\t\treturn\n+\t\tself.redirect_path()\n+\t\tsuper().do_GET()\n+\n+\tdef do_POST(self):\n+\t\tself.redirect_path()\n+\t\tsuper().do_POST()\n+\n+\t# rewrite path of every request that is not gitweb.cgi to out of cgi-bin\n+\tdef redirect_path(self):\n+\t\tif not self.path.startswith(\"/cgi-bin/gitweb.cgi\"):\n+\t\t\tself.path = self.path.replace(\"/cgi-bin/\", \"/\")\n+\n+\t# gitweb.cgi is the only thing that is ever going to be run here.\n+\t# Ignore everything else\n+\tdef is_cgi(self):\n+\t\tresult = False\n+\t\tif self.path.startswith('/cgi-bin/gitweb.cgi'):\n+\t\t\tresult = super().is_cgi()\n+\t\treturn result\n+\n+\n+bind = \"127.0.0.1\"\n+if \"$local\" == \"true\":\n+\tbind = \"0.0.0.0\"\n+\n+# Set our http root directory\n+# This is a work around for a missing directory argument in older Python versions\n+# as this was added to SimpleHTTPRequestHandler in Python 3.7\n+os.chdir(\"$fqgitdir/gitweb/$httpd_only/\")\n+\n+test(HandlerClass=GitWebRequestHandler, port=$port, bind=bind)\n+EOF\n+\n+\tchmod a+x \"$fqgitdir/gitweb/gitweb.py\"\n+}\n+\n gitweb_conf() {\n \tcat > \"$fqgitdir/gitweb/gitweb_config.perl\" <<EOF\n #!@@PERL@@\n@@ -623,6 +732,9 @@ configure_httpd() {\n \t*plackup*)\n \t\tplackup_conf\n \t\t;;\n+\t*python*)\n+\t\tpython_conf\n+\t\t;;\n \t*)\n \t\techo \"Unknown httpd specified: $httpd\"\n \t\texit 1\n\nbase-commit: 16a465bc018d09e9d7bbbdc5f40a7fb99c21f8ef\n-- \n2.20.1\n\n"},{"id":"367598","messageId":"xmqqpnslhj79.fsf@gitster-ct.c.googlers.com","threadId":"50309","inReplyTo":"20190124161331.25945-1-arti.zirk@gmail.com","subject":"Re: [PATCH v1] git-instaweb: Add Python builtin http.server support","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-24T20:52:26Z","receivedAt":"2019-01-24T20:52:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Arti Zirk <arti.zirk@gmail.com> writes:\n\n> With this patch it is possible to launch git-instaweb by using\n> Python 3 http.server CGI handler via `-d python` option.\n>\n> git-instaweb generates a small wrapper around the http.server\n> (in GIT_DIR/gitweb/) ...\n\nI know this follows an existing pattern (psgi and webrick also\nwrites nontrivial amount of code inside GIT_DIR/gitweb), but can we\nsomehow clean it up so that we can do instaweb out of a repository\nwithout writing so much into it first, before adding yet another one\nto make the situation even worse, I wonder?\n\nFor now I'll queue this so that we won't lose sight of the topic,\nbut I am not exactly enthused.\n\n\n\n\n\n\n"},{"id":"367635","messageId":"20190125020451.GU423984@genre.crustytoothpaste.net","threadId":"50309","inReplyTo":"20190124161331.25945-1-arti.zirk@gmail.com","subject":"Re: [PATCH v1] git-instaweb: Add Python builtin http.server support","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2019-01-25T02:04:52Z","receivedAt":"2019-01-25T02:04:59Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On Thu, Jan 24, 2019 at 06:13:31PM +0200, Arti Zirk wrote:\n> With this patch it is possible to launch git-instaweb by using\n> Python 3 http.server CGI handler via `-d python` option.\n> \n> git-instaweb generates a small wrapper around the http.server\n> (in GIT_DIR/gitweb/) that address a limitation of the CGI handler\n> where CGI scripts have to be in a cgi-bin subdirectory and\n> directory index can't be easily changed. To keep the implementation\n> small, gitweb is running on url `/cgi-bin/gitweb.cgi` and an automatic\n> redirection is done when opening `/`.\n> \n> Python 3 is by default installed on most modern Linux distributions\n> which enables running `git instaweb -d python` without needing\n> anything else.\n\nI'm glad we're using Python 3 here, but I wonder if the name \"python\"\nwill lead people to think it will work with Python 2 as well. There are\npeople using up-to-date Git on systems like CentOS 6 and 7, where Python\n3 is not generally available.\n\nCould we call this \"python3\" instead, or provide some other way to\ncommunicate this to the user?\n-- \nbrian m. carlson: Houston, Texas, US\nOpenPGP: https://keybase.io/bk2204\n"},{"id":"367661","messageId":"xmqqva2cg61l.fsf@gitster-ct.c.googlers.com","threadId":"50309","inReplyTo":"20190125020451.GU423984@genre.crustytoothpaste.net","subject":"Re: [PATCH v1] git-instaweb: Add Python builtin http.server support","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-25T14:34:14Z","receivedAt":"2019-01-25T14:34:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"brian m. carlson\" <sandals@crustytoothpaste.net> writes:\n\n> I'm glad we're using Python 3 here, but I wonder if the name \"python\"\n> will lead people to think it will work with Python 2 as well. There are\n> people using up-to-date Git on systems like CentOS 6 and 7, where Python\n> 3 is not generally available.\n>\n> Could we call this \"python3\" instead, or provide some other way to\n> communicate this to the user?\n\nSounds like a good idea.  Also would this be _the_ sole http server\nimplementation Python3 users would choose, or is it just a possible\none?  What I am trying to get at is that we might need to be even\nmore specific than just \"python 3\", but may need to convey that this\nis for \"http.server using python 3\".  I dunno.\n"},{"id":"367663","messageId":"5bc3256d49834c96db2a51c12190f2cb7cf7ac42.camel@gmail.com","threadId":"50309","inReplyTo":"xmqqva2cg61l.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v1] git-instaweb: Add Python builtin http.server support","fromName":"Arti Zirk","fromEmail":"arti.zirk@gmail.com","sentAt":"2019-01-25T15:22:45Z","receivedAt":"2019-01-25T15:22:52Z","isPatch":true,"sender":{"key":"arti.zirk@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1923870?v=4"},"body":"\n> > Could we call this \"python3\" instead, or provide some other way to\n> > communicate this to the user?\n> \n> Sounds like a good idea.  Also would this be _the_ sole http server\n> implementation Python3 users would choose, or is it just a possible\n> one?  What I am trying to get at is that we might need to be even\n> more specific than just \"python 3\", but may need to convey that this\n> is for \"http.server using python 3\".  I dunno.\n\nThis is the built in http server that Python comes with (like Ruby\nusers have builtin webrick server). While it is possible to install\nsomething else, I don't think many casual git-instaweb users would do\nit. \n\nI haven't looked in depth into it but I'm pretty sure that by simply\nchanging the imports I could make this code also work in python2.\n\nUpstream python2 support ends in ~11 months and would Red Hat/CentOS 7\nusers using new git releases really care about \"git instaweb -d python\"\nnot working on installations without Python 3?\n\nIn the end I would like to keep the name just \"python\" to signal that\nit only needs standard Python installation and nothing else.\n\n"},{"id":"367697","messageId":"20190125235811.GW423984@genre.crustytoothpaste.net","threadId":"50309","inReplyTo":"5bc3256d49834c96db2a51c12190f2cb7cf7ac42.camel@gmail.com","subject":"Re: [PATCH v1] git-instaweb: Add Python builtin http.server support","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2019-01-25T23:58:11Z","receivedAt":"2019-01-25T23:58:23Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On Fri, Jan 25, 2019 at 05:22:45PM +0200, Arti Zirk wrote:\n> This is the built in http server that Python comes with (like Ruby\n> users have builtin webrick server). While it is possible to install\n> something else, I don't think many casual git-instaweb users would do\n> it. \n> \n> I haven't looked in depth into it but I'm pretty sure that by simply\n> changing the imports I could make this code also work in python2.\n> \n> Upstream python2 support ends in ~11 months and would Red Hat/CentOS 7\n> users using new git releases really care about \"git instaweb -d python\"\n> not working on installations without Python 3?\n\nI'm sensitive to the fact that upstream is dropping support for Python\n2, and I have no objections to limiting this to Python 3. However,\nwhether we like it or not, Red Hat/CentOS 7 is going to be around for\nfour years after that.\n\n> In the end I would like to keep the name just \"python\" to signal that\n> it only needs standard Python installation and nothing else.\n\nCould you update the documentation to put \"Python 3\" in parentheses or\notherwise make it clear in the documentation? My goal is to avoid\nconfusing users who are on systems that still have Python 2.\n-- \nbrian m. carlson: Houston, Texas, US\nOpenPGP: https://keybase.io/bk2204\n"},{"id":"367806","messageId":"xmqqh8dtejir.fsf@gitster-ct.c.googlers.com","threadId":"50309","inReplyTo":"20190125235811.GW423984@genre.crustytoothpaste.net","subject":"Re: [PATCH v1] git-instaweb: Add Python builtin http.server support","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-28T00:02:52Z","receivedAt":"2019-01-28T00:02:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"brian m. carlson\" <sandals@crustytoothpaste.net> writes:\n\n> On Fri, Jan 25, 2019 at 05:22:45PM +0200, Arti Zirk wrote:\n>> This is the built in http server that Python comes with (like Ruby\n>> users have builtin webrick server). While it is possible to install\n>> something else, I don't think many casual git-instaweb users would do\n>> it. \n>> \n>> I haven't looked in depth into it but I'm pretty sure that by simply\n>> changing the imports I could make this code also work in python2.\n>> \n>> Upstream python2 support ends in ~11 months and would Red Hat/CentOS 7\n>> users using new git releases really care about \"git instaweb -d python\"\n>> not working on installations without Python 3?\n>\n> I'm sensitive to the fact that upstream is dropping support for Python\n> 2, and I have no objections to limiting this to Python 3. However,\n> whether we like it or not, Red Hat/CentOS 7 is going to be around for\n> four years after that.\n>\n>> In the end I would like to keep the name just \"python\" to signal that\n>> it only needs standard Python installation and nothing else.\n>\n> Could you update the documentation to put \"Python 3\" in parentheses or\n> otherwise make it clear in the documentation? My goal is to avoid\n> confusing users who are on systems that still have Python 2.\n\nCalling the option python3 (not python) would give readers the same\nmessage loud and clear in a simpler way, I would think.  Is there\nany reasonable reason why we'd want to avoid saying python3?  It's\nnot like we are afraid of sending an message that we won't stay\nworking with python4 that is in the near horizon ;-), and as Arti\nsays, those who already live in Python3 world would know, when they\nsee either \"python\" or \"python3\", that is what they have anyway no?\n\n\n"},{"id":"367824","messageId":"20190128132458.31401-1-arti.zirk@gmail.com","threadId":"50309","inReplyTo":"20190124161331.25945-1-arti.zirk@gmail.com","subject":"[PATCH v2] git-instaweb: Add Python builtin http.server support","fromName":"Arti Zirk","fromEmail":"arti.zirk@gmail.com","sentAt":"2019-01-28T13:24:59Z","receivedAt":"2019-01-28T13:30:00Z","isPatch":true,"sender":{"key":"arti.zirk@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1923870?v=4"},"body":"With this patch it is possible to launch git-instaweb by using\nPython http.server CGI handler via `-d python` option.\n\ngit-instaweb generates a small wrapper around the http.server\n(in GIT_DIR/gitweb/) that address a limitation of the CGI handler\nwhere CGI scripts have to be in a cgi-bin subdirectory and\ndirectory index can't be easily changed. To keep the implementation\nsmall, gitweb is running on url `/cgi-bin/gitweb.cgi` and an automatic\nredirection is done when opening `/`.\n\nThe generated wrapper is compatible with both Python 2 and 3.\n\nPython is by default installed on most modern Linux distributions\nwhich enables running `git instaweb -d python` without needing\nanything else.\n\nSigned-off-by: Arti Zirk <arti.zirk@gmail.com>\n---\n\nChanges v1..v2:\n - Add compatibily for Python 2, tested with 2.7, 3.4, 3.5, 3.6, 3.7\n\n\nNotes:\n    Base Ref: master\n    Web-Diff: https://github.com/artizirk/git/commit/fe30635765\n    Checkout: git fetch https://github.com/artizirk/git instaweb-python-v2 && git checkout fe30635765\n\n    ### Interdiff (v1..v2):\n\n    diff --git a/git-instaweb.sh b/git-instaweb.sh\n    index c8f9f03447..7c55229773 100755\n    --- a/git-instaweb.sh\n    +++ b/git-instaweb.sh\n    @@ -614,10 +614,11 @@ python_conf() {\n     \tln -sf \"$root/gitweb.cgi\" \"$fqgitdir/gitweb/$httpd_only/cgi-bin/gitweb.cgi\"\n     \tln -sf \"$root/static\" \"$fqgitdir/gitweb/$httpd_only/\"\n\n    -\t# generate a standalone 'python3 http.server' script in $fqgitdir/gitweb\n    -\t# This asumes that python3 is in user's $PATH\n    +\t# generate a standalone 'python http.server' script in $fqgitdir/gitweb\n    +\t# This asumes that python is in user's $PATH\n    +\t# This script is Python 2 and 3 compatible\n     \tcat > \"$fqgitdir/gitweb/gitweb.py\" <<EOF\n    -#!/usr/bin/env python3\n    +#!/usr/bin/env python\n     import os\n     import sys\n\n    @@ -639,7 +640,14 @@ os.dup2(errorlogfile.fileno(), _orig_stderr_fd)\n     sys.stderr = errorlogfile\n\n     from functools import partial\n    -from http.server import CGIHTTPRequestHandler, test\n    +\n    +if sys.version_info < (3, 0):  # Python 2\n    +\tfrom CGIHTTPServer import CGIHTTPRequestHandler\n    +\tfrom BaseHTTPServer import HTTPServer as ServerClass\n    +else:  # Python 3\n    +\tfrom http.server import CGIHTTPRequestHandler\n    +\tfrom http.server import HTTPServer as ServerClass\n    +\n\n     # Those environment variables will be passed to the cgi script\n     os.environ.update({\n    @@ -660,7 +668,7 @@ class GitWebRequestHandler(CGIHTTPRequestHandler):\n\n     \tdef do_HEAD(self):\n     \t\tself.redirect_path()\n    -\t\tsuper().do_HEAD()\n    +\t\tCGIHTTPRequestHandler.do_HEAD(self)\n\n     \tdef do_GET(self):\n     \t\tif self.path == \"/\":\n    @@ -669,11 +677,11 @@ class GitWebRequestHandler(CGIHTTPRequestHandler):\n     \t\t\tself.end_headers()\n     \t\t\treturn\n     \t\tself.redirect_path()\n    -\t\tsuper().do_GET()\n    +\t\tCGIHTTPRequestHandler.do_GET(self)\n\n     \tdef do_POST(self):\n     \t\tself.redirect_path()\n    -\t\tsuper().do_POST()\n    +\t\tCGIHTTPRequestHandler.do_POST(self)\n\n     \t# rewrite path of every request that is not gitweb.cgi to out of cgi-bin\n     \tdef redirect_path(self):\n    @@ -685,7 +693,7 @@ class GitWebRequestHandler(CGIHTTPRequestHandler):\n     \tdef is_cgi(self):\n     \t\tresult = False\n     \t\tif self.path.startswith('/cgi-bin/gitweb.cgi'):\n    -\t\t\tresult = super().is_cgi()\n    +\t\t\tresult = CGIHTTPRequestHandler.is_cgi(self)\n     \t\treturn result\n\n    @@ -698,7 +706,12 @@ if \"$local\" == \"true\":\n     # as this was added to SimpleHTTPRequestHandler in Python 3.7\n     os.chdir(\"$fqgitdir/gitweb/$httpd_only/\")\n\n    -test(HandlerClass=GitWebRequestHandler, port=$port, bind=bind)\n    +GitWebRequestHandler.protocol_version = \"HTTP/1.0\"\n    +httpd = ServerClass((bind, $port), GitWebRequestHandler)\n    +\n    +sa = httpd.socket.getsockname()\n    +print(\"Serving HTTP on\", sa[0], \"port\", sa[1], \"...\")\n    +httpd.serve_forever()\n     EOF\n\n     \tchmod a+x \"$fqgitdir/gitweb/gitweb.py\"\n\n    ### Patches\n\n Documentation/git-instaweb.txt |   3 +-\n git-instaweb.sh                | 127 ++++++++++++++++++++++++++++++++-\n 2 files changed, 128 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-instaweb.txt b/Documentation/git-instaweb.txt\nindex e8ecdbf927..a54fe4401b 100644\n--- a/Documentation/git-instaweb.txt\n+++ b/Documentation/git-instaweb.txt\n@@ -29,7 +29,8 @@ OPTIONS\n \tThe HTTP daemon command-line that will be executed.\n \tCommand-line options may be specified here, and the\n \tconfiguration file will be added at the end of the command-line.\n-\tCurrently apache2, lighttpd, mongoose, plackup and webrick are supported.\n+\tCurrently apache2, lighttpd, mongoose, plackup, python and\n+\twebrick are supported.\n \t(Default: lighttpd)\n\n -m::\ndiff --git a/git-instaweb.sh b/git-instaweb.sh\nindex eec264e630..7c55229773 100755\n--- a/git-instaweb.sh\n+++ b/git-instaweb.sh\n@@ -67,6 +67,13 @@ resolve_full_httpd () {\n \t\thttpd_only=\"${httpd%% *}\" # cut on first space\n \t\treturn\n \t\t;;\n+\t*python*)\n+\t\t# server is started by running via generated gitweb.py in\n+\t\t# $fqgitdir/gitweb\n+\t\tfull_httpd=\"$fqgitdir/gitweb/gitweb.py\"\n+\t\thttpd_only=\"${httpd%% *}\" # cut on first space\n+\t\treturn\n+\t\t;;\n \tesac\n\n \thttpd_only=\"$(echo $httpd | cut -f1 -d' ')\"\n@@ -110,7 +117,7 @@ start_httpd () {\n\n \t# don't quote $full_httpd, there can be arguments to it (-f)\n \tcase \"$httpd\" in\n-\t*mongoose*|*plackup*)\n+\t*mongoose*|*plackup*|*python*)\n \t\t#These servers don't have a daemon mode so we'll have to fork it\n \t\t$full_httpd \"$conf\" &\n \t\t#Save the pid before doing anything else (we'll print it later)\n@@ -595,6 +602,121 @@ EOF\n \trm -f \"$conf\"\n }\n\n+python_conf() {\n+\t# Python's builtin http.server and its CGI support is very limited.\n+\t# CGI handler is capable of running CGI script only from inside a directory.\n+\t# Trying to set cgi_directories=[\"/\"] will add double slash to SCRIPT_NAME\n+\t# and that in turn breaks gitweb's relative link generation.\n+\n+\t# create a simple web root where $fqgitdir/gitweb/$httpd_only is our root\n+\tmkdir -p \"$fqgitdir/gitweb/$httpd_only/cgi-bin\"\n+\t# Python http.server follows the symlinks\n+\tln -sf \"$root/gitweb.cgi\" \"$fqgitdir/gitweb/$httpd_only/cgi-bin/gitweb.cgi\"\n+\tln -sf \"$root/static\" \"$fqgitdir/gitweb/$httpd_only/\"\n+\n+\t# generate a standalone 'python http.server' script in $fqgitdir/gitweb\n+\t# This asumes that python is in user's $PATH\n+\t# This script is Python 2 and 3 compatible\n+\tcat > \"$fqgitdir/gitweb/gitweb.py\" <<EOF\n+#!/usr/bin/env python\n+import os\n+import sys\n+\n+# Open log file in line buffering mode\n+accesslogfile = open(\"$fqgitdir/gitweb/access.log\", 'a', buffering=1)\n+errorlogfile = open(\"$fqgitdir/gitweb/error.log\", 'a', buffering=1)\n+\n+# and replace our stdout and stderr with log files\n+# also do a lowlevel duplicate of the logfile file descriptors so that\n+# our CGI child process writes any stderr warning also to the log file\n+_orig_stdout_fd = sys.stdout.fileno()\n+sys.stdout.close()\n+os.dup2(accesslogfile.fileno(), _orig_stdout_fd)\n+sys.stdout = accesslogfile\n+\n+_orig_stderr_fd = sys.stderr.fileno()\n+sys.stderr.close()\n+os.dup2(errorlogfile.fileno(), _orig_stderr_fd)\n+sys.stderr = errorlogfile\n+\n+from functools import partial\n+\n+if sys.version_info < (3, 0):  # Python 2\n+\tfrom CGIHTTPServer import CGIHTTPRequestHandler\n+\tfrom BaseHTTPServer import HTTPServer as ServerClass\n+else:  # Python 3\n+\tfrom http.server import CGIHTTPRequestHandler\n+\tfrom http.server import HTTPServer as ServerClass\n+\n+\n+# Those environment variables will be passed to the cgi script\n+os.environ.update({\n+\t\"GIT_EXEC_PATH\": \"$GIT_EXEC_PATH\",\n+\t\"GIT_DIR\": \"$GIT_DIR\",\n+\t\"GITWEB_CONFIG\": \"$GITWEB_CONFIG\"\n+})\n+\n+\n+class GitWebRequestHandler(CGIHTTPRequestHandler):\n+\n+\tdef log_message(self, format, *args):\n+\t\t# Write access logs to stdout\n+\t\tsys.stdout.write(\"%s - - [%s] %s\\n\" %\n+\t\t\t\t(self.address_string(),\n+\t\t\t\tself.log_date_time_string(),\n+\t\t\t\tformat%args))\n+\n+\tdef do_HEAD(self):\n+\t\tself.redirect_path()\n+\t\tCGIHTTPRequestHandler.do_HEAD(self)\n+\n+\tdef do_GET(self):\n+\t\tif self.path == \"/\":\n+\t\t\tself.send_response(303, \"See Other\")\n+\t\t\tself.send_header(\"Location\", \"/cgi-bin/gitweb.cgi\")\n+\t\t\tself.end_headers()\n+\t\t\treturn\n+\t\tself.redirect_path()\n+\t\tCGIHTTPRequestHandler.do_GET(self)\n+\n+\tdef do_POST(self):\n+\t\tself.redirect_path()\n+\t\tCGIHTTPRequestHandler.do_POST(self)\n+\n+\t# rewrite path of every request that is not gitweb.cgi to out of cgi-bin\n+\tdef redirect_path(self):\n+\t\tif not self.path.startswith(\"/cgi-bin/gitweb.cgi\"):\n+\t\t\tself.path = self.path.replace(\"/cgi-bin/\", \"/\")\n+\n+\t# gitweb.cgi is the only thing that is ever going to be run here.\n+\t# Ignore everything else\n+\tdef is_cgi(self):\n+\t\tresult = False\n+\t\tif self.path.startswith('/cgi-bin/gitweb.cgi'):\n+\t\t\tresult = CGIHTTPRequestHandler.is_cgi(self)\n+\t\treturn result\n+\n+\n+bind = \"127.0.0.1\"\n+if \"$local\" == \"true\":\n+\tbind = \"0.0.0.0\"\n+\n+# Set our http root directory\n+# This is a work around for a missing directory argument in older Python versions\n+# as this was added to SimpleHTTPRequestHandler in Python 3.7\n+os.chdir(\"$fqgitdir/gitweb/$httpd_only/\")\n+\n+GitWebRequestHandler.protocol_version = \"HTTP/1.0\"\n+httpd = ServerClass((bind, $port), GitWebRequestHandler)\n+\n+sa = httpd.socket.getsockname()\n+print(\"Serving HTTP on\", sa[0], \"port\", sa[1], \"...\")\n+httpd.serve_forever()\n+EOF\n+\n+\tchmod a+x \"$fqgitdir/gitweb/gitweb.py\"\n+}\n+\n gitweb_conf() {\n \tcat > \"$fqgitdir/gitweb/gitweb_config.perl\" <<EOF\n #!@@PERL@@\n@@ -623,6 +745,9 @@ configure_httpd() {\n \t*plackup*)\n \t\tplackup_conf\n \t\t;;\n+\t*python*)\n+\t\tpython_conf\n+\t\t;;\n \t*)\n \t\techo \"Unknown httpd specified: $httpd\"\n \t\texit 1\n\nbase-commit: 16a465bc018d09e9d7bbbdc5f40a7fb99c21f8ef\n--\n2.20.1\n"},{"id":"367835","messageId":"20190128165236.GC423984@genre.crustytoothpaste.net","threadId":"50309","inReplyTo":"20190128132458.31401-1-arti.zirk@gmail.com","subject":"Re: [PATCH v2] git-instaweb: Add Python builtin http.server support","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2019-01-28T16:52:36Z","receivedAt":"2019-01-28T16:52:52Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On Mon, Jan 28, 2019 at 03:24:59PM +0200, Arti Zirk wrote:\n> +\t# generate a standalone 'python http.server' script in $fqgitdir/gitweb\n> +\t# This asumes that python is in user's $PATH\n> +\t# This script is Python 2 and 3 compatible\n> +\tcat > \"$fqgitdir/gitweb/gitweb.py\" <<EOF\n> +#!/usr/bin/env python\n\nI will point out, that despite what the PEPs say, on Debian and\nderivatives, \"python\" will always invoke Python 2, and never Python 3.\n\nThis is probably fine for now, but we'll need to reconsider it before\n2020.\n-- \nbrian m. carlson: Houston, Texas, US\nOpenPGP: https://keybase.io/bk2204\n"},{"id":"367846","messageId":"dcc7522f57ba4bd60412c7dec0528a879027824d.camel@gmail.com","threadId":"50309","inReplyTo":"20190128165236.GC423984@genre.crustytoothpaste.net","subject":"Re: [PATCH v2] git-instaweb: Add Python builtin http.server support","fromName":"Arti Zirk","fromEmail":"arti.zirk@gmail.com","sentAt":"2019-01-28T17:48:57Z","receivedAt":"2019-01-28T17:49:10Z","isPatch":true,"sender":{"key":"arti.zirk@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1923870?v=4"},"body":"> I will point out, that despite what the PEPs say, on Debian and\n> derivatives, \"python\" will always invoke Python 2, and never Python\n> 3.\n> \n> This is probably fine for now, but we'll need to reconsider it before\n> 2020.\n\nIn this case it shouldn't be a problem because I have made sure that it\nworks in both cases.\n\n"},{"id":"367853","messageId":"xmqq4l9sbptu.fsf@gitster-ct.c.googlers.com","threadId":"50309","inReplyTo":"20190128132458.31401-1-arti.zirk@gmail.com","subject":"Re: [PATCH v2] git-instaweb: Add Python builtin http.server support","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-28T18:27:09Z","receivedAt":"2019-01-28T18:27:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Arti Zirk <arti.zirk@gmail.com> writes:\n\n> The generated wrapper is compatible with both Python 2 and 3.\n\n;-)  \n\nYup, that obviously is the best way to settle \"should we make it\nclear that this would not work with Python 2?\" question.\n\n"}]}