From: Arti Zirk <arti.zirk@gmail.com>
To: git@vger.kernel.org
Cc: e@80x24.org, peff@peff.net, jnareb@gmail.com, flavio@polettix.it,
wil@nohakostudios.net, Arti Zirk <arti.zirk@gmail.com>
Subject: [PATCH v1] git-instaweb: Add Python builtin http.server support
Date: Thu, 24 Jan 2019 18:13:31 +0200 [thread overview]
Message-ID: <20190124161331.25945-1-arti.zirk@gmail.com> (raw)
With this patch it is possible to launch git-instaweb by using
Python 3 http.server CGI handler via `-d python` option.
git-instaweb generates a small wrapper around the http.server
(in GIT_DIR/gitweb/) that address a limitation of the CGI handler
where CGI scripts have to be in a cgi-bin subdirectory and
directory index can't be easily changed. To keep the implementation
small, gitweb is running on url `/cgi-bin/gitweb.cgi` and an automatic
redirection is done when opening `/`.
Python 3 is by default installed on most modern Linux distributions
which enables running `git instaweb -d python` without needing
anything else.
Signed-off-by: Arti Zirk <arti.zirk@gmail.com>
---
Notes:
Base Ref: master
Web-Diff: https://github.com/artizirk/git/commit/a40d28ca58
Checkout: git fetch https://github.com/artizirk/git instaweb-python-v1 && git checkout a40d28ca58
Documentation/git-instaweb.txt | 3 +-
git-instaweb.sh | 114 ++++++++++++++++++++++++++++++++-
2 files changed, 115 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-instaweb.txt b/Documentation/git-instaweb.txt
index e8ecdbf927..a54fe4401b 100644
--- a/Documentation/git-instaweb.txt
+++ b/Documentation/git-instaweb.txt
@@ -29,7 +29,8 @@ OPTIONS
The HTTP daemon command-line that will be executed.
Command-line options may be specified here, and the
configuration file will be added at the end of the command-line.
- Currently apache2, lighttpd, mongoose, plackup and webrick are supported.
+ Currently apache2, lighttpd, mongoose, plackup, python and
+ webrick are supported.
(Default: lighttpd)
-m::
diff --git a/git-instaweb.sh b/git-instaweb.sh
index eec264e630..c8f9f03447 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -67,6 +67,13 @@ resolve_full_httpd () {
httpd_only="${httpd%% *}" # cut on first space
return
;;
+ *python*)
+ # server is started by running via generated gitweb.py in
+ # $fqgitdir/gitweb
+ full_httpd="$fqgitdir/gitweb/gitweb.py"
+ httpd_only="${httpd%% *}" # cut on first space
+ return
+ ;;
esac
httpd_only="$(echo $httpd | cut -f1 -d' ')"
@@ -110,7 +117,7 @@ start_httpd () {
# don't quote $full_httpd, there can be arguments to it (-f)
case "$httpd" in
- *mongoose*|*plackup*)
+ *mongoose*|*plackup*|*python*)
#These servers don't have a daemon mode so we'll have to fork it
$full_httpd "$conf" &
#Save the pid before doing anything else (we'll print it later)
@@ -595,6 +602,108 @@ EOF
rm -f "$conf"
}
+python_conf() {
+ # Python's builtin http.server and its CGI support is very limited.
+ # CGI handler is capable of running CGI script only from inside a directory.
+ # Trying to set cgi_directories=["/"] will add double slash to SCRIPT_NAME
+ # and that in turn breaks gitweb's relative link generation.
+
+ # create a simple web root where $fqgitdir/gitweb/$httpd_only is our root
+ mkdir -p "$fqgitdir/gitweb/$httpd_only/cgi-bin"
+ # Python http.server follows the symlinks
+ ln -sf "$root/gitweb.cgi" "$fqgitdir/gitweb/$httpd_only/cgi-bin/gitweb.cgi"
+ ln -sf "$root/static" "$fqgitdir/gitweb/$httpd_only/"
+
+ # generate a standalone 'python3 http.server' script in $fqgitdir/gitweb
+ # This asumes that python3 is in user's $PATH
+ cat > "$fqgitdir/gitweb/gitweb.py" <<EOF
+#!/usr/bin/env python3
+import os
+import sys
+
+# Open log file in line buffering mode
+accesslogfile = open("$fqgitdir/gitweb/access.log", 'a', buffering=1)
+errorlogfile = open("$fqgitdir/gitweb/error.log", 'a', buffering=1)
+
+# and replace our stdout and stderr with log files
+# also do a lowlevel duplicate of the logfile file descriptors so that
+# our CGI child process writes any stderr warning also to the log file
+_orig_stdout_fd = sys.stdout.fileno()
+sys.stdout.close()
+os.dup2(accesslogfile.fileno(), _orig_stdout_fd)
+sys.stdout = accesslogfile
+
+_orig_stderr_fd = sys.stderr.fileno()
+sys.stderr.close()
+os.dup2(errorlogfile.fileno(), _orig_stderr_fd)
+sys.stderr = errorlogfile
+
+from functools import partial
+from http.server import CGIHTTPRequestHandler, test
+
+# Those environment variables will be passed to the cgi script
+os.environ.update({
+ "GIT_EXEC_PATH": "$GIT_EXEC_PATH",
+ "GIT_DIR": "$GIT_DIR",
+ "GITWEB_CONFIG": "$GITWEB_CONFIG"
+})
+
+
+class GitWebRequestHandler(CGIHTTPRequestHandler):
+
+ def log_message(self, format, *args):
+ # Write access logs to stdout
+ sys.stdout.write("%s - - [%s] %s\n" %
+ (self.address_string(),
+ self.log_date_time_string(),
+ format%args))
+
+ def do_HEAD(self):
+ self.redirect_path()
+ super().do_HEAD()
+
+ def do_GET(self):
+ if self.path == "/":
+ self.send_response(303, "See Other")
+ self.send_header("Location", "/cgi-bin/gitweb.cgi")
+ self.end_headers()
+ return
+ self.redirect_path()
+ super().do_GET()
+
+ def do_POST(self):
+ self.redirect_path()
+ super().do_POST()
+
+ # rewrite path of every request that is not gitweb.cgi to out of cgi-bin
+ def redirect_path(self):
+ if not self.path.startswith("/cgi-bin/gitweb.cgi"):
+ self.path = self.path.replace("/cgi-bin/", "/")
+
+ # gitweb.cgi is the only thing that is ever going to be run here.
+ # Ignore everything else
+ def is_cgi(self):
+ result = False
+ if self.path.startswith('/cgi-bin/gitweb.cgi'):
+ result = super().is_cgi()
+ return result
+
+
+bind = "127.0.0.1"
+if "$local" == "true":
+ bind = "0.0.0.0"
+
+# Set our http root directory
+# This is a work around for a missing directory argument in older Python versions
+# as this was added to SimpleHTTPRequestHandler in Python 3.7
+os.chdir("$fqgitdir/gitweb/$httpd_only/")
+
+test(HandlerClass=GitWebRequestHandler, port=$port, bind=bind)
+EOF
+
+ chmod a+x "$fqgitdir/gitweb/gitweb.py"
+}
+
gitweb_conf() {
cat > "$fqgitdir/gitweb/gitweb_config.perl" <<EOF
#!@@PERL@@
@@ -623,6 +732,9 @@ configure_httpd() {
*plackup*)
plackup_conf
;;
+ *python*)
+ python_conf
+ ;;
*)
echo "Unknown httpd specified: $httpd"
exit 1
base-commit: 16a465bc018d09e9d7bbbdc5f40a7fb99c21f8ef
--
2.20.1
next reply other threads:[~2019-01-24 16:13 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-01-24 16:13 Arti Zirk [this message]
2019-01-24 20:52 ` [PATCH v1] git-instaweb: Add Python builtin http.server support Junio C Hamano
2019-01-25 2:04 ` brian m. carlson
2019-01-25 14:34 ` Junio C Hamano
2019-01-25 15:22 ` Arti Zirk
2019-01-25 23:58 ` brian m. carlson
2019-01-28 0:02 ` Junio C Hamano
2019-01-28 13:24 ` [PATCH v2] " Arti Zirk
2019-01-28 16:52 ` brian m. carlson
2019-01-28 17:48 ` Arti Zirk
2019-01-28 18:27 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190124161331.25945-1-arti.zirk@gmail.com \
--to=arti.zirk@gmail.com \
--cc=e@80x24.org \
--cc=flavio@polettix.it \
--cc=git@vger.kernel.org \
--cc=jnareb@gmail.com \
--cc=peff@peff.net \
--cc=wil@nohakostudios.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).