finger/cmd/cmd.go
Gustavo Maronato f96dda4af2
Some checks failed
Go / checks (push) Failing after 52s
refactor and add tests
2023-09-20 01:26:38 -03:00

99 lines
2.7 KiB
Go

package cmd
import (
"context"
"errors"
"fmt"
"os"
"os/signal"
"syscall"
"git.maronato.dev/maronato/finger/internal/config"
"github.com/peterbourgon/ff/v4"
"github.com/peterbourgon/ff/v4/ffhelp"
)
func Run(version string) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Allow graceful shutdown
trapSignalsCrossPlatform(cancel)
cfg := &config.Config{}
// Create a new root command
subcommands := []*ff.Command{
newServerCmd(cfg),
newHealthcheckCmd(cfg),
}
cmd := newRootCmd(version, cfg, subcommands)
// Parse and run
if err := cmd.ParseAndRun(ctx, os.Args[1:], ff.WithEnvVarPrefix("WF")); err != nil {
if errors.Is(err, ff.ErrHelp) || errors.Is(err, ff.ErrNoExec) {
fmt.Fprintf(os.Stderr, "\n%s\n", ffhelp.Command(cmd))
return nil
}
return fmt.Errorf("error running command: %w", err)
}
return nil
}
// https://github.com/caddyserver/caddy/blob/fbb0ecfa322aa7710a3448453fd3ae40f037b8d1/sigtrap.go#L37
// trapSignalsCrossPlatform captures SIGINT or interrupt (depending
// on the OS), which initiates a graceful shutdown. A second SIGINT
// or interrupt will forcefully exit the process immediately.
func trapSignalsCrossPlatform(cancel context.CancelFunc) {
go func() {
shutdown := make(chan os.Signal, 1)
signal.Notify(shutdown, os.Interrupt, syscall.SIGINT)
for i := 0; true; i++ {
<-shutdown
if i > 0 {
fmt.Printf("\nForce quit\n") //nolint:forbidigo // We want to print to stdout
os.Exit(1)
}
fmt.Printf("\nGracefully shutting down. Press Ctrl+C again to force quit\n") //nolint:forbidigo // We want to print to stdout
cancel()
}
}()
}
// NewRootCmd parses the command line flags and returns a config.Config struct.
func newRootCmd(version string, cfg *config.Config, subcommands []*ff.Command) *ff.Command {
fs := ff.NewFlagSet(appName)
for _, cmd := range subcommands {
cmd.Flags = ff.NewFlagSet(cmd.Name).SetParent(fs)
}
cmd := &ff.Command{
Name: appName,
Usage: fmt.Sprintf("%s <command> [flags]", appName),
ShortHelp: fmt.Sprintf("(%s) A webfinger server", version),
Flags: fs,
Subcommands: subcommands,
}
// Use 0.0.0.0 as the default host if on docker
defaultHost := "localhost"
if os.Getenv("ENV_DOCKER") == "true" {
defaultHost = "0.0.0.0"
}
fs.BoolVar(&cfg.Debug, 'd', "debug", "Enable debug logging")
fs.StringVar(&cfg.Host, 'h', "host", defaultHost, "Host to listen on")
fs.StringVar(&cfg.Port, 'p', "port", "8080", "Port to listen on")
fs.StringVar(&cfg.URNPath, 'u', "urn-file", "urns.yml", "Path to the URNs file")
fs.StringVar(&cfg.FingerPath, 'f', "finger-file", "fingers.yml", "Path to the fingers file")
return cmd
}