diff --git a/home/bin/SimpleHTTPServer b/home/bin/SimpleHTTPServer new file mode 100755 index 0000000..13a86cc --- /dev/null +++ b/home/bin/SimpleHTTPServer @@ -0,0 +1,57 @@ +#!/usr/bin/env gosh +package main + +// SimpleHTTPServer is a simple Go static file server, similar to the Python +// module of the same name, but which supports high concurrency and all the +// other niceties that you get from Go out of the box. +// +// It runs via my `gosh` wrapper for treating simple Go programs as shell +// scripts. See my `gosh` script, or just remove the shebang line at the top +// of this file to `go build` your own version. + +import ( + "flag" + "fmt" + "log" + "net/http" +) + +// LogMiddleware logs all HTTP requests. +func LogMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + res := &ResponseWriter{w, 200} + next.ServeHTTP(res, r) + log.Printf("%s %d %s %s\n", + r.RemoteAddr, + res.Status, + r.Method, + r.RequestURI, + ) + }) +} + +// ResponseWriter is my own wrapper around http.ResponseWriter that lets me +// capture its status code, for logging purposes. +type ResponseWriter struct { + http.ResponseWriter + Status int +} + +// WriteHeader wraps http.WriteHeader to also capture the status code. +func (w *ResponseWriter) WriteHeader(code int) { + w.ResponseWriter.WriteHeader(code) + w.Status = code +} + +func main() { + // Command line flag: the port number to listen on. + port := flag.Int("port", 8000, "The port number to listen on.") + flag.Parse() + + fmt.Printf("Serving at http://0.0.0.0:%d/\n", *port) + err := http.ListenAndServe( + fmt.Sprintf(":%d", *port), + LogMiddleware(http.FileServer(http.Dir("."))), + ) + panic(err) +} diff --git a/home/bin/gosh b/home/bin/gosh new file mode 100755 index 0000000..e2795ee --- /dev/null +++ b/home/bin/gosh @@ -0,0 +1,56 @@ +#!/usr/bin/env python + +"""gosh: use Golang as a shell scripting language. + +This is written in Python so that I don't have to commit any binaries to my +dotfiles repo, and my Go shell scripts can also remain in source form. + +Usage: write a Go program with this shebang comment on top immediately before +the `package main` statement: + + #!/usr/bin/env gosh + package main + +And make it executable and run it like any shell script. +""" + +import codecs +import os +import subprocess +import sys +import tempfile + +def main(): + if len(sys.argv) == 1: + die("Usage: gosh ") + + # Get the Go source file from the command line. + source = sys.argv[1] + argv = sys.argv[2:] + if not os.path.isfile(source): + die("{}: not a file".format(source)) + + # Make a temp file that lacks the shebang line of the input file. + with codecs.open(source, "r", "utf-8") as fh: + # Get the shebang off and sanity check it. + shebang = fh.readline() + if not "gosh" in shebang: + die("{}: doesn't appear to be a Go script".format(source)) + + # Write it to a temp file, sans shebang. + temp = tempfile.NamedTemporaryFile(delete=False, suffix=".go") + temp.write(fh.read().strip()) + temp.close() + + # Call it. + subprocess.call(["go", "run", temp.name] + argv) + + # Clean up. + os.unlink(temp.name) + +def die(message): + print(message) + sys.exit(1) + +if __name__ == "__main__": + main()