Skip to content

Commit

Permalink
Refactor: split flag setup, usage reporting etc
Browse files Browse the repository at this point in the history
  • Loading branch information
mgumz committed Nov 19, 2023
1 parent d768201 commit a5d54a8
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 105 deletions.
15 changes: 8 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
PROJECT=knut
PKG=github.com/mgumz/$(PROJECT)
VERSION=$(shell cat VERSION)
BUILD_DATE=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
GIT_HASH=$(shell git rev-parse HEAD)
Expand All @@ -9,18 +10,19 @@ TARGETS=linux.amd64 \
linux.386 \
linux.arm64 \
linux.mips64 \
windows.amd64.exe \
freebsd.amd64 \
darwin.amd64 \
darwin.arm64
darwin.arm64 \
windows.amd64.exe \
freebsd.amd64

BINARIES=$(addprefix bin/$(PROJECT)-$(VERSION)., $(TARGETS))
RELEASES=$(subst windows.amd64.tar.gz,windows.amd64.zip,$(foreach r,$(subst .exe,,$(TARGETS)),releases/$(PROJECT)-$(VERSION).$(r).tar.gz))

LDFLAGS=-ldflags "-X main.Version=$(VERSION) -X main.BuildDate=$(BUILD_DATE) -X main.GitHash=$(GIT_HASH)"
LDFLAGS=-ldflags "-X $(PKG)/internal/pkg/knut.Version=$(VERSION) \
-X $(PKG)/internal/pkg/knut.BuildDate=$(BUILD_DATE) \
-X $(PKG)/internal/pkg/knut.GitHash=$(GIT_HASH)"

$(PROJECT):
go build -v -o $@ ./cmd/$(PROJECT)
$(PROJECT): bin/$(PROJECT)

######################################################
## release related
Expand All @@ -33,7 +35,6 @@ list-releases:
clean:
rm -f $(BINARIES) $(RELEASES)

$(PROJECT): bin/$(PROJECT)
bin/$(PROJECT): cmd/$(PROJECT) bin
go build -v -o $@ ./$<

Expand Down
28 changes: 18 additions & 10 deletions cmd/knut/doc.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// generated, do not edit.

package main

/*
knut [opts] [uri:]folder-or-file [mapping2] [mapping3] [...]
Expand Down Expand Up @@ -29,24 +33,28 @@ Mapping Format:
to the given http-host
/uri:git://folder/ - serves files via "git http-backend"
/uri:cgit://path/to/dir - serves git-repos via "cgit"
/uri:myip:// - serves a "myip" endpoint
Options:
Options:
-auth string
use 'name:password' to require
use 'name:password' to require
-bind string
address to bind to (default ":8080")
address to bind to (default ":8080")
-compress
handle "Accept-Encoding" = "gzip,deflate" (default true)
handle "Accept-Encoding" = "gzip,deflate" (default true)
-log
log requests to stdout (default true)
log requests to stdout (default true)
-server-id string
add "Server: <val-here>" to the response (default "knut/1.0")
add "Server: <val-here>" to the response (default "knut/dev-build")
-tls-cert string
use given cert to start tls
use given cert to start tls
-tls-key string
use given key to start tls
use given key to start tls
-tls-onetime
use a onetime-in-memory cert+key to drive tls
use a onetime-in-memory cert+key to drive tls
-version
print version
*/
package main
37 changes: 37 additions & 0 deletions cmd/knut/gen_doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//go:build ignore

package main

import (
"bytes"
"flag"
"fmt"
"os"

"github.com/mgumz/knut/internal/pkg/knut"
)

func main() {

oname := flag.String("o", "", "name of generated file")
flag.Parse()

ofile := os.Stdout
if *oname != "" {
ofile, _ = os.Create(*oname)
defer ofile.Close()
}

kf := flag.NewFlagSet("knut", flag.ContinueOnError)
knut.SetupFlags(kf)
b := bytes.NewBuffer(nil)
kf.SetOutput(b)
kf.Usage()
fmt.Fprintln(ofile, "// generated, do not edit.")
fmt.Fprintln(ofile)
fmt.Fprintln(ofile, "package main")
fmt.Fprintln(ofile)
fmt.Fprintln(ofile, "/*")
fmt.Fprintln(ofile, string(b.Bytes()))
fmt.Fprintln(ofile, "*/")
}
111 changes: 23 additions & 88 deletions cmd/knut/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

package main

//go:generate go run -v ./gen_doc.go -o doc.go

import (
"flag"
"fmt"
Expand All @@ -15,98 +17,28 @@ import (
"github.com/mgumz/knut/internal/pkg/knut"
)

var (
Version = "dev-build"
GitHash = ""
BuildDate = ""
)

func usage() {
flag.CommandLine.SetOutput(os.Stdout)
fmt.Println(`
knut [opts] [uri:]folder-or-file [mapping2] [mapping3] [...]
Sample:
knut file.txt /this/:. /ding.txt:/tmp/dong.txt
Mapping Format:
file.txt - publish the file "file.txt" via "/file.txt"
/:. - list contents of current directory via "/"
/uri:folder - list contents of "folder" via "/uri"
/uri:file - serve "file" via "/uri"
/uri:@text - respond with "text" at "/uri"
30x/uri:location - respond with 301 at "/uri"
@/upload:folder - accept multipart encoded data via POST at "/upload"
and store it inside "folder". A simple upload form
is rendered on GET.
/c.tgz:tar+gz://./ - creates a (gzipped) tarball from the current directory
and serves it via "/c.tgz"
/z.zip:zip://./ - creates a zip files from the current directory
and serves it via "/z.zip"
/z.zip:zipfs://a.zip - list and servce the content of the entries of an
existing "z.zip" via the "/z.zip": consider a file
"example.txt" inside "z.zip", it will be directly
available via "/z.zip/example.txt"
/uri:http://1.2.3.4/ - creates a reverse proxy and forwards requests to /uri
to the given http-host
/uri:git://folder/ - serves files via "git http-backend"
/uri:cgit://path/to/dir - serves git-repos via "cgit"
/uri:myip:// - serves a "myip" endpoint
Options:
`)
flag.PrintDefaults()
fmt.Println()
}

func main() {

opts := struct {
bindAddr string
doLog bool
doAuth string
doCompress bool
doPrintVersion bool
addServerID string
tlsOnetime bool
tlsCert string
tlsKey string
}{
bindAddr: ":8080",
doLog: true,
doCompress: true,
addServerID: "knut/" + Version,
}
opts := knut.SetupFlags(flag.CommandLine)

flag.StringVar(&opts.bindAddr, "bind", opts.bindAddr, "address to bind to")
flag.BoolVar(&opts.doLog, "log", opts.doLog, "log requests to stdout")
flag.BoolVar(&opts.doCompress, "compress", opts.doCompress, `handle "Accept-Encoding" = "gzip,deflate"`)
flag.StringVar(&opts.doAuth, "auth", "", "use 'name:password' to require")
flag.StringVar(&opts.addServerID, "server-id", opts.addServerID, `add "Server: <val-here>" to the response`)
flag.BoolVar(&opts.tlsOnetime, "tls-onetime", opts.tlsOnetime, "use a onetime-in-memory cert+key to drive tls")
flag.StringVar(&opts.tlsKey, "tls-key", opts.tlsKey, "use given key to start tls")
flag.StringVar(&opts.tlsCert, "tls-cert", opts.tlsCert, "use given cert to start tls")
flag.BoolVar(&opts.doPrintVersion, "version", opts.doPrintVersion, "print version")
flag.Usage = usage
flag.CommandLine.SetOutput(os.Stdout)
flag.Parse()

if opts.doPrintVersion {
fmt.Println(Version, GitHash, BuildDate)
if opts.DoPrintVersion {
fmt.Println(knut.Version, knut.GitHash, knut.BuildDate)
os.Exit(0)
}

if flag.NArg() == 0 {
fmt.Fprintf(os.Stderr, "error: missing mapping\n")
usage()
flag.Usage()
os.Exit(1)
}

tree, nHandlers := prepareTrees(http.NewServeMux(), flag.Args())
if nHandlers == 0 {
fmt.Fprintf(os.Stderr, "error: not one valid mapping given\n")
usage()
flag.Usage()
os.Exit(1)
}

Expand All @@ -115,22 +47,22 @@ func main() {
//
var h = http.Handler(tree)

if opts.addServerID != "" {
h = knut.AddServerIDHandler(h, opts.addServerID)
if opts.AddServerID != "" {
h = knut.AddServerIDHandler(h, opts.AddServerID)
}
h = knut.NoCacheHandler(h)
if opts.doCompress {
if opts.DoCompress {
h = knut.CompressHandler(h)
}
if opts.doAuth != "" {
parts := strings.SplitN(opts.doAuth, ":", 2)
if opts.DoAuth != "" {
parts := strings.SplitN(opts.DoAuth, ":", 2)
if len(parts) == 0 {
fmt.Fprintf(os.Stderr, "error: missing separator for argument to -auth")
os.Exit(1)
}
h = knut.BasicAuthHandler(h, parts[0], parts[1])
}
if opts.doLog {
if opts.DoLog {
h = knut.LogRequestHandler(h, os.Stdout)
}

Expand All @@ -139,20 +71,23 @@ func main() {
//
var run func() error
switch {
case opts.tlsOnetime:
case opts.TlsOnetime:
onetime := &knut.OnetimeTLS{}
if err := onetime.Create(opts.bindAddr); err != nil {
if err := onetime.Create(opts.BindAddr); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
run = func() error { return http.Serve(onetime.Listener, h) }
case opts.tlsCert != "" && opts.tlsKey != "":
run = func() error { return http.ListenAndServeTLS(opts.bindAddr, opts.tlsCert, opts.tlsKey, h) }
case opts.TlsCert != "" && opts.TlsKey != "":
run = func() error {
server := &http.Server{Addr: opts.BindAddr, Handler: h}
return server.ListenAndServeTLS(opts.TlsCert, opts.TlsKey)
}
default:
run = func() error { return http.ListenAndServe(opts.bindAddr, h) }
run = func() error { return http.ListenAndServe(opts.BindAddr, h) }
}

fmt.Printf("\nknut started on %s, be aware of the trees!\n\n", opts.bindAddr)
fmt.Printf("\nknut started on %s, be aware of the trees!\n\n", opts.BindAddr)
if err := run(); err != nil {
fmt.Printf("error: %v\n", err)
os.Exit(1)
Expand Down
41 changes: 41 additions & 0 deletions internal/pkg/knut/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2015 Mathias Gumz. All rights reserved. Use of this source code
// is governed by a BSD-style license that can be found in the LICENSE file.

package knut

import "flag"

type Opts struct {
BindAddr string
DoLog bool
DoAuth string
DoCompress bool
DoPrintVersion bool
AddServerID string
TlsOnetime bool
TlsCert string
TlsKey string
}

func SetupFlags(f *flag.FlagSet) *Opts {

opts := Opts{
BindAddr: ":8080",
DoLog: true,
DoCompress: true,
AddServerID: "knut/" + Version,
}

f.StringVar(&opts.BindAddr, "bind", opts.BindAddr, "address to bind to")
f.BoolVar(&opts.DoLog, "log", opts.DoLog, "log requests to stdout")
f.BoolVar(&opts.DoCompress, "compress", opts.DoCompress, `handle "Accept-Encoding" = "gzip,deflate"`)
f.StringVar(&opts.DoAuth, "auth", "", "use 'name:password' to require")
f.StringVar(&opts.AddServerID, "server-id", opts.AddServerID, `add "Server: <val-here>" to the response`)
f.BoolVar(&opts.TlsOnetime, "tls-onetime", opts.TlsOnetime, "use a onetime-in-memory cert+key to drive tls")
f.StringVar(&opts.TlsKey, "tls-key", opts.TlsKey, "use given key to start tls")
f.StringVar(&opts.TlsCert, "tls-cert", opts.TlsCert, "use given cert to start tls")
f.BoolVar(&opts.DoPrintVersion, "version", opts.DoPrintVersion, "print version")
f.Usage = func() { printUsage(f) }

return &opts
}
51 changes: 51 additions & 0 deletions internal/pkg/knut/usage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2015 Mathias Gumz. All rights reserved. Use of this source code
// is governed by a BSD-style license that can be found in the LICENSE file.

package knut

import (
"flag"
"fmt"
)

const usageText = `
knut [opts] [uri:]folder-or-file [mapping2] [mapping3] [...]
Sample:
knut file.txt /this/:. /ding.txt:/tmp/dong.txt
Mapping Format:
file.txt - publish the file "file.txt" via "/file.txt"
/:. - list contents of current directory via "/"
/uri:folder - list contents of "folder" via "/uri"
/uri:file - serve "file" via "/uri"
/uri:@text - respond with "text" at "/uri"
30x/uri:location - respond with 301 at "/uri"
@/upload:folder - accept multipart encoded data via POST at "/upload"
and store it inside "folder". A simple upload form
is rendered on GET.
/c.tgz:tar+gz://./ - creates a (gzipped) tarball from the current directory
and serves it via "/c.tgz"
/z.zip:zip://./ - creates a zip files from the current directory
and serves it via "/z.zip"
/z.zip:zipfs://a.zip - list and servce the content of the entries of an
existing "z.zip" via the "/z.zip": consider a file
"example.txt" inside "z.zip", it will be directly
available via "/z.zip/example.txt"
/uri:http://1.2.3.4/ - creates a reverse proxy and forwards requests to /uri
to the given http-host
/uri:git://folder/ - serves files via "git http-backend"
/uri:cgit://path/to/dir - serves git-repos via "cgit"
/uri:myip:// - serves a "myip" endpoint
`

func printUsage(fs *flag.FlagSet) {
w := fs.Output()
fmt.Fprintln(w, usageText, "Options:")
fmt.Fprintln(w)
fs.PrintDefaults()
fmt.Fprintln(w)
}
Loading

0 comments on commit a5d54a8

Please sign in to comment.