Skip to content

Commit 731f620

Browse files
committed
git-bundle-web-server: move flags definition to common location
Move the definition of flags used by 'git-bundle-web-server' & custom flag validation, to a more openly-accessible location. Specifically, add the function 'WebServerFlags()' to a new file 'common-args.go' (in a new command 'utils' library). This function returns two values: a 'flag.FlagSet' containing the args that are used by 'git-bundle-web-server', and a function that takes no arguments and runs validation checks on the flag values after arg parsing. The goal of this change is to avoid duplicating these arg definitions and validations when 'git-bundle-server web-server start' eventually uses those options to configure the server daemon. It also sets up a pattern we can use for future commands that need to share options. Additionally, because the access pattern for flag values in a parsed 'flag.FlagSet' is a bit weird, add another helper function to 'common-args.go' to contain the logic for getting those values. Signed-off-by: Victoria Dye <[email protected]>
1 parent a0a7ccc commit 731f620

File tree

2 files changed

+72
-14
lines changed

2 files changed

+72
-14
lines changed

cmd/git-bundle-web-server/main.go

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@ package main
22

33
import (
44
"context"
5+
"flag"
56
"fmt"
67
"log"
78
"net/http"
89
"os"
910
"os/signal"
10-
"strconv"
1111
"strings"
1212
"sync"
1313
"syscall"
1414

15+
"github.com/github/git-bundle-server/cmd/utils"
1516
"github.com/github/git-bundle-server/internal/argparse"
1617
"github.com/github/git-bundle-server/internal/core"
1718
)
@@ -102,31 +103,29 @@ func startServer(server *http.Server,
102103

103104
func main() {
104105
parser := argparse.NewArgParser("git-bundle-web-server [--port <port>] [--cert <filename> --key <filename>]")
105-
port := parser.String("port", "8080", "The port on which the server should be hosted")
106-
cert := parser.String("cert", "", "The path to the X.509 SSL certificate file to use in securely hosting the server")
107-
key := parser.String("key", "", "The path to the certificate's private key")
106+
flags, validate := utils.WebServerFlags(parser)
107+
flags.VisitAll(func(f *flag.Flag) {
108+
parser.Var(f.Value, f.Name, f.Usage)
109+
})
108110
parser.Parse(os.Args[1:])
111+
validate()
109112

110-
// Additional option validation
111-
p, err := strconv.Atoi(*port)
112-
if err != nil || p < 0 || p > 65535 {
113-
parser.Usage("Invalid port '%s'.", *port)
114-
}
115-
if (*cert == "") != (*key == "") {
116-
parser.Usage("Both '--cert' and '--key' are needed to specify SSL configuration.")
117-
}
113+
// Get the flag values
114+
port := utils.GetFlagValue[string](parser, "port")
115+
cert := utils.GetFlagValue[string](parser, "cert")
116+
key := utils.GetFlagValue[string](parser, "key")
118117

119118
// Configure the server
120119
mux := http.NewServeMux()
121120
mux.HandleFunc("/", serve)
122121
server := &http.Server{
123122
Handler: mux,
124-
Addr: ":" + *port,
123+
Addr: ":" + port,
125124
}
126125
serverWaitGroup := &sync.WaitGroup{}
127126

128127
// Start the server asynchronously
129-
startServer(server, *cert, *key, serverWaitGroup)
128+
startServer(server, cert, key, serverWaitGroup)
130129

131130
// Intercept interrupt signals
132131
c := make(chan os.Signal, 1)

cmd/utils/common-args.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package utils
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"strconv"
7+
)
8+
9+
// Helpers
10+
11+
// Forward declaration (kinda) of argParser.
12+
// 'argparse.argParser' is private, but we want to be able to pass instances
13+
// of it to functions, so we need to define an interface that includes the
14+
// functions we want to call from the parser.
15+
type argParser interface {
16+
Lookup(name string) *flag.Flag
17+
Usage(errFmt string, args ...any)
18+
}
19+
20+
func GetFlagValue[T any](parser argParser, name string) T {
21+
flagVal := parser.Lookup(name)
22+
if flagVal == nil {
23+
panic(fmt.Sprintf("flag '--%s' is undefined", name))
24+
}
25+
26+
flagGetter, ok := flagVal.Value.(flag.Getter)
27+
if !ok {
28+
panic(fmt.Sprintf("flag '--%s' is invalid (does not implement flag.Getter)", name))
29+
}
30+
31+
value, ok := flagGetter.Get().(T)
32+
if !ok {
33+
panic(fmt.Sprintf("flag '--%s' is invalid (cannot cast to appropriate type)", name))
34+
}
35+
36+
return value
37+
}
38+
39+
// Sets of flags shared between multiple commands/programs
40+
41+
func WebServerFlags(parser argParser) (*flag.FlagSet, func()) {
42+
f := flag.NewFlagSet("", flag.ContinueOnError)
43+
port := f.String("port", "8080", "The port on which the server should be hosted")
44+
cert := f.String("cert", "", "The path to the X.509 SSL certificate file to use in securely hosting the server")
45+
key := f.String("key", "", "The path to the certificate's private key")
46+
47+
// Function to call for additional arg validation (may exit with 'Usage()')
48+
validationFunc := func() {
49+
p, err := strconv.Atoi(*port)
50+
if err != nil || p < 0 || p > 65535 {
51+
parser.Usage("Invalid port '%s'.", *port)
52+
}
53+
if (*cert == "") != (*key == "") {
54+
parser.Usage("Both '--cert' and '--key' are needed to specify SSL configuration.")
55+
}
56+
}
57+
58+
return f, validationFunc
59+
}

0 commit comments

Comments
 (0)