-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: adds flag to install specified version (#7)
* feat: add flag to install specified version * fix: typo * fix: linter
- Loading branch information
1 parent
70dabaf
commit 27d93e9
Showing
8 changed files
with
511 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package flags | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
|
||
terminalColors "github.com/fatih/color" | ||
) | ||
|
||
// Flag contains the information for the flag. | ||
type Flag struct { | ||
// The name of the flag | ||
name string | ||
|
||
// A boolean that represents if the flag expects a value to be passed. | ||
// | ||
// e.g. --install-version 21.3 | ||
acceptsVale bool | ||
} | ||
|
||
// getHelpName returns the name for the flag and an indicator | ||
// if the flag expects a value of not. | ||
// | ||
// For example, when a flag does not expect a value the result will be like: --some-flag. | ||
// If the flag expects a value, the result will be like: --some-flag=value | ||
func (f Flag) getHelpName() string { | ||
flagName := fmt.Sprintf("--%s", f.name) | ||
if f.acceptsVale { | ||
flagName += "=value" | ||
} | ||
|
||
return flagName | ||
} | ||
|
||
// FlagSet is the struct that will be used to set up the flags for the CLI. | ||
type FlagSet struct { | ||
// An array of the flags that are available. | ||
// flags is used as a store to easy iterate on the flags. | ||
flags []Flag | ||
} | ||
|
||
// FlagBool defines a bool flag with specified name, default value, and usage string. | ||
// The argument p points to a bool variable in which to store the value of the flag. | ||
// FlagBool also appends the flag to the FlagSet array. | ||
func (s *FlagSet) FlagBool(p *bool, name string, value bool, usage string) { | ||
s.flags = append(s.flags, Flag{name: name, acceptsVale: false}) | ||
flag.BoolVar(p, name, value, usage) | ||
} | ||
|
||
// StringVar defines a string flag with specified name, default value, and usage string. | ||
// The argument p points to a string variable in which to store the value of the flag. | ||
// FlagBool also appends the flag to the FlagSet array. | ||
func (s *FlagSet) FlagStr(p *string, name string, value string, usage string) { | ||
s.flags = append(s.flags, Flag{name: name, acceptsVale: true}) | ||
flag.StringVar(p, name, value, usage) | ||
} | ||
|
||
// printSynopsis returns back all the available flags without any description. | ||
// All the flags are iterated from FlagSet array that contains the flags. | ||
func (s *FlagSet) printSynopsis() { | ||
msg := " gvs\n" | ||
for _, flag := range s.flags { | ||
msg += fmt.Sprintf(" [%s]\n", flag.getHelpName()) | ||
} | ||
|
||
fmt.Printf("%s\n", msg) | ||
} | ||
|
||
// printFlags returns back all the available flags wiath a description. | ||
// All the flags are iterated from FlagSet array that contains the flags. | ||
func (s *FlagSet) printFlags() { | ||
flagSet := flag.CommandLine | ||
|
||
for _, flag := range s.flags { | ||
flagInfo := flagSet.Lookup(flag.name) | ||
fmt.Printf(" %s\n\t%s\n", flag.getHelpName(), flagInfo.Usage) | ||
} | ||
} | ||
|
||
// Parse is preparing the help command and parses the flags. | ||
func (s *FlagSet) Parse() { | ||
flag.Usage = func() { | ||
bold := terminalColors.New().Add(terminalColors.Bold) | ||
|
||
gvsMessage := bold.Sprint("gvs") | ||
|
||
fmt.Println() | ||
bold.Println("NAME") | ||
fmt.Printf(" gvs - go version manager\n\n") | ||
|
||
bold.Println("DESCRIPTION") | ||
fmt.Printf(" the %s CLI is a command line tool to manage multiple active Go versions.\n\n", gvsMessage) | ||
|
||
bold.Println("SYNOPSIS") | ||
s.printSynopsis() | ||
|
||
bold.Println("FLAGS") | ||
s.printFlags() | ||
|
||
fmt.Println() | ||
fmt.Printf("Before start using the %s CLI, make sure to delete all the existing go versions\n", gvsMessage) | ||
fmt.Printf("and append to your profile file the export: %q.\n", "export PATH=$PATH:$HOME/bin") | ||
fmt.Printf("The profile file could be one of: (%s)\n", "~/.bash_profile, ~/.zshrc, ~/.profile, or ~/.bashrc") | ||
} | ||
|
||
flag.Parse() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// Package version provides an interface to make handle | ||
// the CLI logic for the versions. | ||
package version | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// Semver contains the version split into semantic version structure. | ||
// Semver can have either a patch or a release candidate value, not both at the same time. | ||
type Semver struct { | ||
// Contains the major version of the semantic structure. | ||
Major *uint64 | ||
|
||
// Contains the minor version of the semantic structure. | ||
Minor *uint64 | ||
|
||
// Contains the patch version of the semantic structure. | ||
Patch *uint64 | ||
|
||
// Contains the release candidate number of the semantic structure. | ||
ReleaseCandidate *uint64 | ||
} | ||
|
||
// GetVersion returns back the stringified representation of the semantic version structure. | ||
func (s Semver) GetVersion() string { | ||
semver := "" | ||
|
||
if s.Major == nil { | ||
return "" | ||
} | ||
|
||
semver += fmt.Sprint(*s.Major) | ||
|
||
if s.Minor != nil { | ||
semver += fmt.Sprintf(".%d", *s.Minor) | ||
} | ||
|
||
if s.Patch != nil { | ||
semver += fmt.Sprintf(".%d", *s.Patch) | ||
} else if s.ReleaseCandidate != nil { | ||
semver += fmt.Sprintf("rc%d", *s.ReleaseCandidate) | ||
} | ||
|
||
return semver | ||
} | ||
|
||
// parseNumber converts a string into *uint64. | ||
// In case of an error while converting the value, parseNumber return nil. | ||
func parseNumber(str string) *uint64 { | ||
num, err := strconv.ParseUint(str, 10, 64) | ||
|
||
if err != nil { | ||
return nil | ||
} | ||
|
||
return &num | ||
} | ||
|
||
// ParseSemver parses the given stringified version into a semantic version structure. | ||
// | ||
// If the parse is successful it will store it | ||
// in the value pointed to by semver. | ||
// | ||
// If the parse fails, ParseSemver will return an error. | ||
func ParseSemver(version string, semver *Semver) error { | ||
var major *uint64 | ||
var minor *uint64 | ||
var patch *uint64 | ||
var rc *uint64 | ||
|
||
r := regexp.MustCompile(`(\d{1,2})(\.?\d{1,2})?(\.?\d{1,2}|rc\d{1,2})?`) | ||
|
||
if !r.MatchString(version) { | ||
return errors.New("invalid Go version") | ||
} | ||
|
||
groups := r.FindStringSubmatch(version)[1:] | ||
major = parseNumber(groups[0]) | ||
minor = parseNumber(strings.TrimPrefix(groups[1], ".")) | ||
|
||
if strings.HasPrefix(groups[2], "rc") { | ||
rc = parseNumber(strings.TrimPrefix(groups[2], "rc")) | ||
} else { | ||
patch = parseNumber(strings.TrimPrefix(groups[2], ".")) | ||
} | ||
|
||
semver.Major = major | ||
semver.Minor = minor | ||
semver.Patch = patch | ||
semver.ReleaseCandidate = rc | ||
|
||
return nil | ||
} |
Oops, something went wrong.