1package git 2 3import ( 4 "bufio" 5 "os" 6 "path/filepath" 7 "regexp" 8 "strings" 9 10 "github.com/mitchellh/go-homedir" 11) 12 13const ( 14 hostReStr = "(?i)^[ \t]*(host|hostname)[ \t]+(.+)$" 15) 16 17type SSHConfig map[string]string 18 19func newSSHConfigReader() *SSHConfigReader { 20 configFiles := []string{ 21 "/etc/ssh_config", 22 "/etc/ssh/ssh_config", 23 } 24 if homedir, err := homedir.Dir(); err == nil { 25 userConfig := filepath.Join(homedir, ".ssh", "config") 26 configFiles = append([]string{userConfig}, configFiles...) 27 } 28 return &SSHConfigReader{ 29 Files: configFiles, 30 } 31} 32 33type SSHConfigReader struct { 34 Files []string 35} 36 37func (r *SSHConfigReader) Read() SSHConfig { 38 config := make(SSHConfig) 39 hostRe := regexp.MustCompile(hostReStr) 40 41 for _, filename := range r.Files { 42 r.readFile(config, hostRe, filename) 43 } 44 45 return config 46} 47 48func (r *SSHConfigReader) readFile(c SSHConfig, re *regexp.Regexp, f string) error { 49 file, err := os.Open(f) 50 if err != nil { 51 return err 52 } 53 defer file.Close() 54 55 hosts := []string{"*"} 56 scanner := bufio.NewScanner(file) 57 for scanner.Scan() { 58 line := scanner.Text() 59 match := re.FindStringSubmatch(line) 60 if match == nil { 61 continue 62 } 63 64 names := strings.Fields(match[2]) 65 if strings.EqualFold(match[1], "host") { 66 hosts = names 67 } else { 68 for _, host := range hosts { 69 for _, name := range names { 70 c[host] = expandTokens(name, host) 71 } 72 } 73 } 74 } 75 76 return scanner.Err() 77} 78 79func expandTokens(text, host string) string { 80 re := regexp.MustCompile(`%[%h]`) 81 return re.ReplaceAllStringFunc(text, func(match string) string { 82 switch match { 83 case "%h": 84 return host 85 case "%%": 86 return "%" 87 } 88 return "" 89 }) 90} 91