github.com/iwataka/ghq@v0.7.5-0.20160611155400-0aa07ac077a9/git.go (about) 1 package main 2 3 import ( 4 "os" 5 "os/exec" 6 "regexp" 7 "strconv" 8 "strings" 9 "syscall" 10 11 "github.com/motemen/ghq/utils" 12 ) 13 14 // GitConfigSingle fetches single git-config variable. 15 // returns an empty string and no error if no variable is found with the given key. 16 func GitConfigSingle(key string) (string, error) { 17 return GitConfig("--get", key) 18 } 19 20 // GitConfigAll fetches git-config variable of multiple values. 21 func GitConfigAll(key string) ([]string, error) { 22 value, err := GitConfig("--get-all", key) 23 if err != nil { 24 return nil, err 25 } 26 27 // No results found, return an empty slice 28 if value == "" { 29 return nil, nil 30 } 31 32 return strings.Split(value, "\000"), nil 33 } 34 35 // GitConfig invokes 'git config' and handles some errors properly. 36 func GitConfig(args ...string) (string, error) { 37 gitArgs := append([]string{"config", "--path", "--null"}, args...) 38 cmd := exec.Command("git", gitArgs...) 39 cmd.Stderr = os.Stderr 40 41 buf, err := cmd.Output() 42 43 if exitError, ok := err.(*exec.ExitError); ok { 44 if waitStatus, ok := exitError.Sys().(syscall.WaitStatus); ok { 45 if waitStatus.ExitStatus() == 1 { 46 // The key was not found, do not treat as an error 47 return "", nil 48 } 49 } 50 51 return "", err 52 } 53 54 return strings.TrimRight(string(buf), "\000"), nil 55 } 56 57 var versionRx = regexp.MustCompile(`(\d+)\.(\d+)\.(\d+)`) 58 59 var featureConfigURLMatchVersion = []uint{1, 8, 5} 60 61 func GitHasFeatureConfigURLMatch() bool { 62 cmd := exec.Command("git", "--version") 63 buf, err := cmd.Output() 64 65 if err != nil { 66 return false 67 } 68 69 return gitVersionOutputSatisfies(string(buf), featureConfigURLMatchVersion) 70 } 71 72 func gitVersionOutputSatisfies(gitVersionOutput string, baseVersionParts []uint) bool { 73 versionStrings := versionRx.FindStringSubmatch(gitVersionOutput) 74 if versionStrings == nil { 75 return false 76 } 77 78 for i, v := range baseVersionParts { 79 thisV64, err := strconv.ParseUint(versionStrings[i+1], 10, 0) 80 utils.PanicIf(err) 81 82 thisV := uint(thisV64) 83 84 if thisV > v { 85 return true 86 } else if v == thisV { 87 continue 88 } else { 89 return false 90 } 91 } 92 93 return true 94 }