From 53f97d6a1c8ac107c9140fed8b50ef0730bf8a39 Mon Sep 17 00:00:00 2001 From: Daniel Rocha Date: Tue, 26 Apr 2022 09:16:42 +0200 Subject: [PATCH] refactor: use cobra to handle CLI arguments --- cmd/htp/main.go | 125 +++++++++++++++++++++++++----------------------- go.mod | 10 +++- go.sum | 10 ++++ 3 files changed, 84 insertions(+), 61 deletions(-) diff --git a/cmd/htp/main.go b/cmd/htp/main.go index 2d2bfae..a16938e 100644 --- a/cmd/htp/main.go +++ b/cmd/htp/main.go @@ -1,9 +1,7 @@ package main import ( - "flag" "fmt" - "log" "os" "os/exec" "runtime" @@ -11,6 +9,7 @@ import ( "time" "github.com/danroc/htp/pkg/htp" + "github.com/spf13/cobra" ) const ( @@ -20,53 +19,78 @@ const ( second = int64(time.Second) ) -type options struct { - host string - count uint - verbose bool - date bool - sync bool - format string -} +func buildRootCommand() *cobra.Command { + var ( + host string + silent bool + format string + sync bool + date bool + count int + timeout int + ) -func main() { - opts := parseArgs() - if !strings.Contains(opts.host, "://") { - opts.host = "https://" + opts.host - } + cmd := &cobra.Command{ + Use: "htp", + Short: "HTP - Date and time from HTTP headers", + RunE: func(cmd *cobra.Command, args []string) error { + if !strings.Contains(host, "://") { + host = "https://" + host + } - logger := log.New(os.Stderr, "", 0) - model := htp.NewSyncModel() - client, err := htp.NewSyncClient(opts.host, 10*time.Second) - if err != nil { - logger.Fatal("Cannot create client: ", err) - } + client, err := htp.NewSyncClient(host, time.Duration(timeout)*time.Second) + if err != nil { + return nil + } + + model := htp.NewSyncModel() + + options := &htp.SyncOptions{ + Count: int(count), + Trace: func(round *htp.SyncRound) { + if !silent { + fmt.Fprintf(os.Stderr, "offset: %+.3f (±%.3f) seconds\n", + toSec(model.Offset()), toSec(model.Margin())) + } + }, + } + + if err := htp.Sync(client, model, options); err != nil { + return err + } + + if date { + now := time.Now().Add(time.Duration(-model.Offset())) + fmt.Printf("%s\n", now.Format(format)) + } else { + fmt.Printf("%+.3f\n", toSec(-model.Offset())) + } - options := &htp.SyncOptions{ - Count: int(opts.count), - Trace: func(round *htp.SyncRound) { - if opts.verbose { - offset := model.Offset() - margin := model.Margin() - logger.Printf("offset: %+.3f (±%.3f) seconds\n", toSec(offset), toSec(margin)) + if sync { + if err := syncSystem(model.Offset()); err != nil { + return fmt.Errorf("cannot set system clock: %w", err) + } } + + return nil }, } - if err = htp.Sync(client, model, options); err != nil { - logger.Fatal("Cannot sync clock: ", err) - } - if opts.date { - now := time.Now().Add(time.Duration(-model.Offset())) - fmt.Printf("%s\n", now.Format(opts.format)) - } else { - fmt.Printf("%+.3f\n", toSec(-model.Offset())) - } + cmd.Flags().IntVarP(&count, "num-requests", "n", 10, "Number of requests") + cmd.Flags().IntVarP(&timeout, "timeout", "t", 10, "Timeout in seconds") + cmd.Flags().BoolVarP(&silent, "silent", "s", false, "Do not show offsets") + cmd.Flags().BoolVarP(&date, "date", "d", false, "Show date and time instead of offset") + cmd.Flags().BoolVarP(&sync, "set", "e", false, "Set system time") + cmd.Flags().StringVarP(&format, "format", "f", time.UnixDate, "Date and time format") + cmd.Flags().StringVarP(&host, "url", "u", "https://www.google.com", "Host URL") + + return cmd +} - if opts.sync { - if err := syncSystem(model.Offset()); err != nil { - logger.Fatal("Cannot set system clock: ", err) - } +func main() { + cmd := buildRootCommand() + if err := cmd.Execute(); err != nil { + os.Exit(1) } } @@ -89,25 +113,6 @@ func syncSystem(offset int64) error { } } -func parseArgs() *options { - flag.Usage = func() { - fmt.Fprintf(flag.CommandLine.Output(), - "HTP - Date and time from HTTP headers\n\nUsage:\n") - flag.PrintDefaults() - } - - opts := options{} - flag.StringVar(&opts.host, "u", "https://www.google.com", "Host URL") - flag.UintVar(&opts.count, "n", 8, "Number of requests") - flag.BoolVar(&opts.verbose, "v", false, "Show offsets during synchronization") - flag.BoolVar(&opts.date, "d", false, "Display date and time instead of offset") - flag.StringVar(&opts.format, "f", time.UnixDate, "Date and time format") - flag.BoolVar(&opts.sync, "s", false, "Synchronize system time") - flag.Parse() - - return &opts -} - func toSec(t int64) float64 { return float64(t) / float64(second) } diff --git a/go.mod b/go.mod index 6fc8344..1a2cad3 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,12 @@ module github.com/danroc/htp go 1.18 -require golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd +require ( + github.com/spf13/cobra v1.4.0 + golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd +) + +require ( + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect +) diff --git a/go.sum b/go.sum index e47c56d..d7357a7 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,12 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd h1:zVFyTKZN/Q7mNRWSs1GOYnHM9NiFSJ54YVRsD0rNWT4= golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=