From 4bbbb553df9bc07f866b22e7803453d14070f502 Mon Sep 17 00:00:00 2001 From: Evsyukov Denis Date: Tue, 3 Sep 2024 14:33:27 +0300 Subject: [PATCH 1/7] feat: new flag options for cache --- cmd/gobrew/main.go | 79 +++++++++++++++++++++++++++----------- cmd/gobrew/main_unix.go | 2 +- cmd/gobrew/main_windows.go | 2 +- go.mod | 1 + go.sum | 2 + gobrew.go | 14 +++++++ helpers.go | 17 +++++--- 7 files changed, 88 insertions(+), 29 deletions(-) diff --git a/cmd/gobrew/main.go b/cmd/gobrew/main.go index 5046f0f..3a84298 100644 --- a/cmd/gobrew/main.go +++ b/cmd/gobrew/main.go @@ -1,11 +1,15 @@ package main import ( - "flag" + "fmt" "log" "os" + "regexp" "strconv" "strings" + "time" + + flag "github.com/spf13/pflag" "github.com/kevincobain2000/gobrew" "github.com/kevincobain2000/gobrew/utils" @@ -16,6 +20,11 @@ var actionArg = "" var versionArg = "" var version = "dev" +var help bool +var clearCache bool +var ttl time.Duration +var disableCache bool + var allowedArgs = []string{ "h", "help", @@ -37,11 +46,25 @@ func init() { if !isArgAllowed() { log.Println("[Info] Invalid usage") - log.Print(usage()) + flag.Usage() return } + flag.BoolVarP(&disableCache, "disable-cache", "d", false, "disable local cache") + flag.BoolVarP(&clearCache, "clear-cache", "c", false, "clear local cache") + flag.DurationVarP(&ttl, "ttl", "t", 20*time.Minute, "set cache duration in minutes") + + flag.BoolVarP(&help, "help", "h", false, "show usage message") + + flag.Usage = Usage + flag.Parse() + + if help { + Usage() + return + } + args = flag.Args() if len(args) == 0 { actionArg = "interactive" @@ -92,6 +115,9 @@ func main() { GobrewDownloadURL: gobrew.DownloadURL, GobrewTags: gobrew.TagsAPI, GobrewVersionsURL: gobrew.VersionsURL, + TTL: ttl, + DisableCache: disableCache, + ClearCache: clearCache, } gb := gobrew.NewGoBrew(config) @@ -101,7 +127,7 @@ func main() { case "noninteractive": gb.Interactive(false) case "h", "help": - log.Print(usage()) + flag.Usage() case "ls", "list": gb.ListVersions() case "ls-remote": @@ -124,17 +150,22 @@ func main() { } } +// isArgAllowed checks if the arg is allowed +// but ignored flags +// +// if the any arg is not allowed, it will return false func isArgAllowed() bool { ok := true - if len(os.Args) > 1 { - _, ok = Find(allowedArgs, os.Args[1]) - if !ok { - return false + for i := range os.Args { + if i == 0 { + continue + } + arg := os.Args[i] + if strings.HasPrefix(arg, "-") { + continue } - } - if len(os.Args) > 2 { - _, ok = Find(allowedArgs, os.Args[1]) + ok = Find(allowedArgs, arg) if !ok { return false } @@ -145,22 +176,21 @@ func isArgAllowed() bool { // Find takes a slice and looks for an element in it. If found it will // return it's key, otherwise it will return -1 and a bool of false. -func Find(slice []string, val string) (int, bool) { - for i, item := range slice { +func Find(slice []string, val string) bool { + r := regexp.MustCompile("([0-9]+).([0-9]+)*|beta.*|rc.*|latest") + if matches := r.FindString(val); matches != "" { + return true + } + + for _, item := range slice { if item == val { - return i, true + return true } } - return -1, false + return false } -func usage() string { - usageMsg := - ` -# Add gobrew to your ~/.bashrc or ~/.zshrc -export PATH="$HOME/.gobrew/current/bin:$HOME/.gobrew/bin:$PATH" -export GOROOT="$HOME/.gobrew/current/go" -` +var Usage = func() { msg := ` gobrew ` + version + ` @@ -178,6 +208,11 @@ Usage: gobrew version Show gobrew version gobrew help Show this message +Options: + gobrew [--clear-cache | -c] clear gobrew cache + gobrew [--disable-cache | -d] disable gobrew cache + gobrew [--ttl=20m | -t 20m] set gobrew cache ttl, default 20m + Examples: gobrew use 1.16 # use go version 1.16 gobrew use 1.16.1 # use go version 1.16.1 @@ -195,5 +230,5 @@ Examples: Installation Path: ` + usageMsg - return msg + fmt.Fprintf(os.Stderr, "%s\n", msg) } diff --git a/cmd/gobrew/main_unix.go b/cmd/gobrew/main_unix.go index 311dbd2..fa0816f 100644 --- a/cmd/gobrew/main_unix.go +++ b/cmd/gobrew/main_unix.go @@ -2,7 +2,7 @@ package main -const usageMsg = ` +const usageMsg string = ` # Add gobrew to your ~/.bashrc or ~/.zshrc export PATH="$HOME/.gobrew/current/bin:$HOME/.gobrew/bin:$PATH" export GOROOT="$HOME/.gobrew/current/go" diff --git a/cmd/gobrew/main_windows.go b/cmd/gobrew/main_windows.go index 52bdcda..e783409 100644 --- a/cmd/gobrew/main_windows.go +++ b/cmd/gobrew/main_windows.go @@ -2,7 +2,7 @@ package main -const usageMsg = ` +const usageMsg string = ` # Add gobrew to your environment variables PATH="%USERPROFILE%\.gobrew\current\bin;%USERPROFILE%\.gobrew\bin;%PATH%" GOROOT="%USERPROFILE%\.gobrew\current\go" diff --git a/go.mod b/go.mod index e5eb0d7..0611317 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/ulikunitz/xz v0.5.11 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect golang.org/x/sys v0.17.0 // indirect diff --git a/go.sum b/go.sum index 6c14b31..fd0a1c3 100644 --- a/go.sum +++ b/go.sum @@ -33,6 +33,8 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/schollz/progressbar/v3 v3.14.1 h1:VD+MJPCr4s3wdhTc7OEJ/Z3dAeBzJ7yKH/P4lC5yRTI= github.com/schollz/progressbar/v3 v3.14.1/go.mod h1:Zc9xXneTzWXF81TGoqL71u0sBPjULtEHYtj/WVgVy8E= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= diff --git a/gobrew.go b/gobrew.go index 43e9b90..9bddf47 100644 --- a/gobrew.go +++ b/gobrew.go @@ -11,6 +11,7 @@ import ( "sort" "strconv" "strings" + "time" "github.com/Masterminds/semver" "github.com/gookit/color" @@ -56,6 +57,7 @@ type GoBrew struct { currentBinDir string currentGoDir string downloadsDir string + cacheFile string Config } @@ -65,11 +67,18 @@ type Config struct { GobrewDownloadURL string GobrewTags string GobrewVersionsURL string + + // cache settings + TTL time.Duration + DisableCache bool + ClearCache bool } // NewGoBrew instance func NewGoBrew(config Config) GoBrew { installDir := filepath.Join(config.RootDir, goBrewDir) + cacheFile := filepath.Join(installDir, "cache.json") + gb := GoBrew{ Config: config, installDir: installDir, @@ -78,6 +87,11 @@ func NewGoBrew(config Config) GoBrew { currentBinDir: filepath.Join(installDir, "current", "bin"), currentGoDir: filepath.Join(installDir, "current", "go"), downloadsDir: filepath.Join(installDir, "downloads"), + cacheFile: cacheFile, + } + + if gb.ClearCache { + _ = os.RemoveAll(gb.cacheFile) } return gb diff --git a/helpers.go b/helpers.go index 1f40e9f..4cf23d7 100644 --- a/helpers.go +++ b/helpers.go @@ -528,9 +528,12 @@ type Cache struct { } func (gb *GoBrew) getVersionsFromCache() []string { - cacheFile := filepath.Join(gb.installDir, "cache.json") - if _, err := os.Stat(cacheFile); err == nil { - data, e := os.ReadFile(cacheFile) + if gb.DisableCache { + return []string{} + } + + if _, err := os.Stat(gb.cacheFile); err == nil { + data, e := os.ReadFile(gb.cacheFile) if e != nil { return []string{} } @@ -545,8 +548,8 @@ func (gb *GoBrew) getVersionsFromCache() []string { return []string{} } - // cache for 20 minutes - if time.Now().UTC().After(timestamp.Add(20 * time.Minute)) { + // cache for gb.TTL duration + if time.Now().UTC().After(timestamp.Add(gb.TTL)) { return []string{} } @@ -557,6 +560,10 @@ func (gb *GoBrew) getVersionsFromCache() []string { } func (gb *GoBrew) saveVersionsToCache(versions []string) { + if gb.DisableCache { + return + } + cacheFile := filepath.Join(gb.installDir, "cache.json") var cache = Cache{ Timestamp: time.Now().UTC().Format(time.RFC3339), From f644f2a38f9ee2835565c06cc470eecec16e012b Mon Sep 17 00:00:00 2001 From: Evsyukov Denis Date: Tue, 3 Sep 2024 15:18:09 +0300 Subject: [PATCH 2/7] fix: invalid usage message --- cmd/gobrew/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/gobrew/main.go b/cmd/gobrew/main.go index 3a84298..9394c3e 100644 --- a/cmd/gobrew/main.go +++ b/cmd/gobrew/main.go @@ -46,7 +46,7 @@ func init() { if !isArgAllowed() { log.Println("[Info] Invalid usage") - flag.Usage() + Usage() return } From 971e555c5284d1c538c25ba5d3b2efbc91b4c14e Mon Sep 17 00:00:00 2001 From: Evsyukov Denis Date: Wed, 4 Sep 2024 09:34:00 +0300 Subject: [PATCH 3/7] fix: check first arg is allowed --- cmd/gobrew/main.go | 81 +++++++++++++++------------------------------- 1 file changed, 26 insertions(+), 55 deletions(-) diff --git a/cmd/gobrew/main.go b/cmd/gobrew/main.go index 9394c3e..2c75449 100644 --- a/cmd/gobrew/main.go +++ b/cmd/gobrew/main.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "os" - "regexp" "strconv" "strings" "time" @@ -15,7 +14,6 @@ import ( "github.com/kevincobain2000/gobrew/utils" ) -var args []string var actionArg = "" var versionArg = "" var version = "dev" @@ -25,31 +23,25 @@ var clearCache bool var ttl time.Duration var disableCache bool -var allowedArgs = []string{ - "h", - "help", - "ls", - "list", - "ls-remote", - "install", - "use", - "uninstall", - "interactive", - "noninteractive", - "prune", - "version", - "self-update", +var allowedArgs = map[string]struct{}{ + "h": {}, + "help": {}, + "ls": {}, + "list": {}, + "ls-remote": {}, + "install": {}, + "use": {}, + "uninstall": {}, + "interactive": {}, + "noninteractive": {}, + "prune": {}, + "version": {}, + "self-update": {}, } func init() { log.SetFlags(0) - if !isArgAllowed() { - log.Println("[Info] Invalid usage") - Usage() - return - } - flag.BoolVarP(&disableCache, "disable-cache", "d", false, "disable local cache") flag.BoolVarP(&clearCache, "clear-cache", "c", false, "clear local cache") flag.DurationVarP(&ttl, "ttl", "t", 20*time.Minute, "set cache duration in minutes") @@ -60,12 +52,18 @@ func init() { flag.Parse() + args := flag.Args() + if !isArgAllowed(args) { + log.Println("[Info] Invalid usage") + Usage() + return + } + if help { Usage() return } - args = flag.Args() if len(args) == 0 { actionArg = "interactive" } else { @@ -154,40 +152,13 @@ func main() { // but ignored flags // // if the any arg is not allowed, it will return false -func isArgAllowed() bool { - ok := true - for i := range os.Args { - if i == 0 { - continue - } - arg := os.Args[i] - if strings.HasPrefix(arg, "-") { - continue - } - - ok = Find(allowedArgs, arg) - if !ok { - return false - } - } - - return ok -} - -// Find takes a slice and looks for an element in it. If found it will -// return it's key, otherwise it will return -1 and a bool of false. -func Find(slice []string, val string) bool { - r := regexp.MustCompile("([0-9]+).([0-9]+)*|beta.*|rc.*|latest") - if matches := r.FindString(val); matches != "" { - return true +func isArgAllowed(args []string) bool { + if len(args) > 0 { + _, ok := allowedArgs[args[0]] + return ok } - for _, item := range slice { - if item == val { - return true - } - } - return false + return true } var Usage = func() { From 5e4242da0a73c5f79c4e7ef4a3a297a717d65dcf Mon Sep 17 00:00:00 2001 From: Evsyukov Denis Date: Wed, 4 Sep 2024 09:38:05 +0300 Subject: [PATCH 4/7] chore: Usage func and change comment --- cmd/gobrew/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/gobrew/main.go b/cmd/gobrew/main.go index 2c75449..e16d880 100644 --- a/cmd/gobrew/main.go +++ b/cmd/gobrew/main.go @@ -125,7 +125,7 @@ func main() { case "noninteractive": gb.Interactive(false) case "h", "help": - flag.Usage() + Usage() case "ls", "list": gb.ListVersions() case "ls-remote": @@ -151,7 +151,7 @@ func main() { // isArgAllowed checks if the arg is allowed // but ignored flags // -// if the any arg is not allowed, it will return false +// we check only the first argument, the command func isArgAllowed(args []string) bool { if len(args) > 0 { _, ok := allowedArgs[args[0]] From 02b9846cbff2cf7c1306e67a29b88885f6b2ebb2 Mon Sep 17 00:00:00 2001 From: Evsyukov Denis Date: Wed, 4 Sep 2024 10:12:11 +0300 Subject: [PATCH 5/7] fix: process invalid cmd flags with custom message --- cmd/gobrew/main.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmd/gobrew/main.go b/cmd/gobrew/main.go index e16d880..b39a924 100644 --- a/cmd/gobrew/main.go +++ b/cmd/gobrew/main.go @@ -8,7 +8,7 @@ import ( "strings" "time" - flag "github.com/spf13/pflag" + "github.com/spf13/pflag" "github.com/kevincobain2000/gobrew" "github.com/kevincobain2000/gobrew/utils" @@ -42,6 +42,7 @@ var allowedArgs = map[string]struct{}{ func init() { log.SetFlags(0) + flag := pflag.NewFlagSet("gobrew", pflag.ContinueOnError) flag.BoolVarP(&disableCache, "disable-cache", "d", false, "disable local cache") flag.BoolVarP(&clearCache, "clear-cache", "c", false, "clear local cache") flag.DurationVarP(&ttl, "ttl", "t", 20*time.Minute, "set cache duration in minutes") @@ -50,7 +51,11 @@ func init() { flag.Usage = Usage - flag.Parse() + if err := flag.Parse(os.Args[1:]); err != nil { + log.Println("[Info] Invalid usage") + Usage() + return + } args := flag.Args() if !isArgAllowed(args) { From 7c39b7fd9c0527d4f8e7aa5e35631a74bec06844 Mon Sep 17 00:00:00 2001 From: Evsyukov Denis Date: Wed, 4 Sep 2024 11:46:51 +0300 Subject: [PATCH 6/7] fix: improve command validation --- cmd/gobrew/main.go | 56 ++++++++++------------------------------------ 1 file changed, 12 insertions(+), 44 deletions(-) diff --git a/cmd/gobrew/main.go b/cmd/gobrew/main.go index b39a924..0887f4d 100644 --- a/cmd/gobrew/main.go +++ b/cmd/gobrew/main.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "github.com/gookit/color" "github.com/spf13/pflag" "github.com/kevincobain2000/gobrew" @@ -23,22 +24,6 @@ var clearCache bool var ttl time.Duration var disableCache bool -var allowedArgs = map[string]struct{}{ - "h": {}, - "help": {}, - "ls": {}, - "list": {}, - "ls-remote": {}, - "install": {}, - "use": {}, - "uninstall": {}, - "interactive": {}, - "noninteractive": {}, - "prune": {}, - "version": {}, - "self-update": {}, -} - func init() { log.SetFlags(0) @@ -49,26 +34,13 @@ func init() { flag.BoolVarP(&help, "help", "h", false, "show usage message") - flag.Usage = Usage - if err := flag.Parse(os.Args[1:]); err != nil { - log.Println("[Info] Invalid usage") + color.Errorln("[Error] Invalid usage") Usage() - return + os.Exit(2) } args := flag.Args() - if !isArgAllowed(args) { - log.Println("[Info] Invalid usage") - Usage() - return - } - - if help { - Usage() - return - } - if len(args) == 0 { actionArg = "interactive" } else { @@ -100,6 +72,11 @@ func init() { } func main() { + if help { + Usage() + return + } + rootDir := os.Getenv("GOBREW_ROOT") if rootDir == "" { var err error @@ -150,22 +127,13 @@ func main() { gb.Version(version) case "self-update": gb.Upgrade(version) + default: + color.Errorln("[Error] Invalid usage") + Usage() + os.Exit(2) } } -// isArgAllowed checks if the arg is allowed -// but ignored flags -// -// we check only the first argument, the command -func isArgAllowed(args []string) bool { - if len(args) > 0 { - _, ok := allowedArgs[args[0]] - return ok - } - - return true -} - var Usage = func() { msg := ` gobrew ` + version + ` From b4d881283e36bb019089e199b7cb60d96a5f3f7a Mon Sep 17 00:00:00 2001 From: Pulkit Kathuria Date: Thu, 5 Sep 2024 10:33:01 +0900 Subject: [PATCH 7/7] (docs) specify package (#210) --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 5c3656f..0ea1cb2 100644 --- a/README.md +++ b/README.md @@ -377,3 +377,13 @@ export GOPATH="$HOME/.gobrew/current/go" - v1.9.4 - `gobrew` interactive - v1.9.8 - bug fix where 1.21 is not detected as 1.21.0 - v1.10.10 - `ls-remote` is blazing fast, cached. +- v1.10.11 - Optional options for cache and ttl. + + +# DEVELOPMENT NOTES + +```sh +go run ./cmd/gobrew -h +golangci-lint run ./... +go test -v ./... +``` \ No newline at end of file